diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml
new file mode 100644
index 0000000..04a23c4
--- /dev/null
+++ b/dependency-reduced-pom.xml
@@ -0,0 +1,145 @@
+
+
+ 4.0.0
+ me.hulipvp.hcf
+ HCF
+ 1.0.0-FORK
+
+ ${basedir}/src/main/java
+ clean package install
+
+
+ .
+ true
+ ${basedir}/src/main/resources/
+
+ *.yml
+
+
+
+ ${project.artifactId}
+
+
+ maven-compiler-plugin
+ 3.7.0
+
+ 1.8
+ 1.8
+
+
+
+ maven-shade-plugin
+ 3.1.1
+
+
+ package
+
+ shade
+
+
+ ${project.artifactId}
+
+
+ org.apache.commons.pool2
+ ${project.groupId}.lib.org.apache.commons.pool2
+
+
+ org.bson
+ ${project.groupId}.lib.org.bson
+
+
+ redis.clients
+ ${project.groupId}.lib.redis.clients
+
+
+ com.google.gson
+ ${project.groupId}.lib.com.google.gson
+
+
+ com.mongodb
+ ${project.groupId}.lib.com.mongodb
+
+
+
+
+
+
+
+
+
+
+ org.github.paperspigot
+ paperspigot-api
+ 1.7.10-R0.1-SNAPSHOT
+ provided
+
+
+ org.github.paperspigot
+ paperspigot
+ 1.7.10-R0.1-SNAPSHOT
+ provided
+
+
+ me.joeleoli.nucleus
+ nucleus
+ 1.0-SNAPSHOT
+ provided
+
+
+ commons-lang3
+ org.apache.commons
+
+
+ httpclient
+ org.apache.httpcomponents
+
+
+ commons-io
+ commons-io
+
+
+
+
+ com.comphenix.protocol
+ ProtocolLib
+ 3.6.5-SNAPSHOT
+ provided
+
+
+ cglib-nodep
+ cglib
+
+
+ BukkitExecutors
+ com.comphenix.executors
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.16.20
+ provided
+
+
+ net.milkbowl.vault
+ VaultAPI
+ LATEST
+ system
+ ${project.basedir}/libs/VaultAPI-1.4.jar
+
+
+ com.verispvp.core
+ core
+ 1.0-SNAPSHOT
+ system
+ ${project.basedir}/libs/core-0.0.1-SNAPSHOT.jar
+
+
+
+ UTF-8
+ 1.8
+ 1.8
+ ${project.groupId}.${project.artifactId}
+
+
diff --git a/libs/Vault.jar b/libs/Vault.jar
new file mode 100644
index 0000000..63fc042
Binary files /dev/null and b/libs/Vault.jar differ
diff --git a/libs/VaultAPI-1.4.jar b/libs/VaultAPI-1.4.jar
new file mode 100644
index 0000000..17a70a2
Binary files /dev/null and b/libs/VaultAPI-1.4.jar differ
diff --git a/libs/core-0.0.1-SNAPSHOT.jar b/libs/core-0.0.1-SNAPSHOT.jar
new file mode 100644
index 0000000..c32bede
Binary files /dev/null and b/libs/core-0.0.1-SNAPSHOT.jar differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..daf7794
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,172 @@
+
+
+ 4.0.0
+
+ me.hulipvp.hcf
+ HCF
+ 1.0.0-FORK
+ jar
+
+
+ ${project.groupId}.${project.artifactId}
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+ ${project.artifactId}
+ clean package install
+ ${basedir}/src/main/java
+
+
+ .
+ true
+ ${basedir}/src/main/resources/
+
+ *.yml
+
+
+
+
+
+ maven-compiler-plugin
+ 3.7.0
+
+ 1.8
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.1.1
+
+
+ package
+
+ shade
+
+
+ ${project.artifactId}
+
+
+ org.apache.commons.pool2
+ ${project.groupId}.lib.org.apache.commons.pool2
+
+
+ org.bson
+ ${project.groupId}.lib.org.bson
+
+
+ redis.clients
+ ${project.groupId}.lib.redis.clients
+
+
+ com.google.gson
+ ${project.groupId}.lib.com.google.gson
+
+
+ com.mongodb
+ ${project.groupId}.lib.com.mongodb
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.github.paperspigot
+ paperspigot-api
+ 1.7.10-R0.1-SNAPSHOT
+ provided
+
+
+ org.github.paperspigot
+ paperspigot
+ 1.7.10-R0.1-SNAPSHOT
+ provided
+
+
+
+
+
+ org.mongodb
+ mongo-java-driver
+ 3.7.0
+
+
+ redis.clients
+ jedis
+ 2.9.0
+
+
+
+
+
+ net.milkbowl.vault
+ VaultAPI
+ LATEST
+ system
+ ${project.basedir}/libs/VaultAPI-1.4.jar
+
+
+ me.joeleoli.nucleus
+ nucleus
+ 1.0-SNAPSHOT
+ provided
+
+
+ com.verispvp.core
+ core
+ 1.0-SNAPSHOT
+ system
+ ${project.basedir}/libs/core-0.0.1-SNAPSHOT.jar
+
+
+ com.comphenix.protocol
+ ProtocolLib
+ 3.6.5-SNAPSHOT
+ provided
+
+
+
+
+
+ com.google.code.gson
+ gson
+ 2.6.2
+
+
+ org.projectlombok
+ lombok
+ 1.16.20
+ provided
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/HCF.java b/src/main/java/me/hulipvp/hcf/HCF.java
new file mode 100644
index 0000000..3fecbaf
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/HCF.java
@@ -0,0 +1,198 @@
+package me.hulipvp.hcf;
+
+import lombok.Getter;
+import me.hulipvp.hcf.api.hooks.plugins.core.CoreHook;
+import me.hulipvp.hcf.api.hooks.plugins.nucleus.NucleusHook;
+import me.hulipvp.hcf.api.hooks.plugins.PlayerHook;
+import me.hulipvp.hcf.api.hooks.plugins.vault.VaultHook;
+import me.hulipvp.hcf.api.hooks.server.ProtocolHook;
+import me.hulipvp.hcf.api.modules.ModuleManager;
+import me.hulipvp.hcf.backend.BackendType;
+import me.hulipvp.hcf.backend.HCFBackend;
+import me.hulipvp.hcf.backend.backends.MongoBackend;
+import me.hulipvp.hcf.backend.backends.RedisBackend;
+import me.hulipvp.hcf.backend.creds.MongoCredentials;
+import me.hulipvp.hcf.backend.creds.RedisCredentials;
+import me.hulipvp.hcf.backend.files.KitsFile;
+import me.hulipvp.hcf.backend.files.LocationsFile;
+import me.hulipvp.hcf.backend.files.MessagesFile;
+import me.hulipvp.hcf.backend.files.ReclaimFile;
+import me.hulipvp.hcf.commands.CommandManager;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.kits.Kit;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.player.data.PlayerLogger;
+import me.hulipvp.hcf.game.player.data.mod.item.ModItems;
+import me.hulipvp.hcf.game.timer.Timer;
+import me.hulipvp.hcf.listeners.ListenerManager;
+import me.hulipvp.hcf.ui.board.BoardManager;
+import me.hulipvp.hcf.ui.board.provider.HCFScoreboard;
+import me.hulipvp.hcf.ui.tab.TablistManager;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.Bukkit;
+import org.bukkit.plugin.java.JavaPlugin;
+
+public class HCF extends JavaPlugin {
+
+ @Getter private static HCF instance;
+
+ @Getter private PlayerHook playerHook;
+
+ @Getter private KitsFile kitsFile;
+ @Getter private LocationsFile locationsFile;
+ @Getter private MessagesFile messagesFile;
+ @Getter private ReclaimFile reclaimFile;
+
+ @Getter private HCFBackend backend;
+
+ @Getter private CommandManager commandManager;
+ @Getter private ListenerManager listenerManager;
+ @Getter private ModuleManager moduleManager;
+ @Getter private BoardManager boardManager;
+ @Getter private TablistManager tablistManager;
+
+ public void onEnable() {
+ instance = this;
+
+ /*=============================*/
+ // Saving config.
+ saveDefaultConfig();
+
+ Locale.load(this, false);
+ /*=============================*/
+
+ /*=============================*/
+ // Loading plugin hooks
+ if(VaultHook.canHook())
+ playerHook = new VaultHook();
+
+ if(NucleusHook.canHook())
+ playerHook = new NucleusHook();
+
+ if(CoreHook.canHook())
+ playerHook = new CoreHook();
+
+ if(ProtocolHook.canHook())
+ new ProtocolHook();
+ /*=============================*/
+
+ /*=============================*/
+ // Loading Backend
+ BackendType type = BackendType.getOrDefault(getConfig().getString("backend.driver"));
+ switch(type) {
+ case REDIS: {
+ backend = new RedisBackend(
+ new RedisCredentials(
+ getConfig().getString("backend.redis.host"),
+ getConfig().getInt("backend.redis.port"),
+ getConfig().getString("backend.redis.pass")
+ )
+ );
+ break;
+ }
+ case MONGO: {
+ backend = new MongoBackend(
+ new MongoCredentials(
+ getConfig().getString("backend.mongo.host"),
+ getConfig().getInt("backend.mongo.port"),
+ getConfig().getString("backend.mongo.auth.username"),
+ getConfig().getString("backend.mongo.auth.password"),
+ getConfig().getString("backend.mongo.database"),
+ getConfig().getString("backend.mongo.auth.authDb")
+ )
+ );
+ break;
+ }
+ }
+
+ if(!backend.isLoaded()) {
+ getLogger().severe("Unable to connect to backend. Shutting down.");
+ Bukkit.getServer().shutdown();
+ }
+ /*=============================*/
+
+ /*=============================*/
+ // Files
+ kitsFile = new KitsFile();
+ locationsFile = new LocationsFile();
+ messagesFile = new MessagesFile();
+ reclaimFile = new ReclaimFile();
+ /*=============================*/
+
+ /*=============================*/
+ // Scoreboard & Tablist
+ boardManager = new BoardManager(new HCFScoreboard());
+ tablistManager = new TablistManager(new HCFTablist());
+ /*=============================*/
+
+ /*=============================*/
+ // Events
+ listenerManager = new ListenerManager();
+ listenerManager.registerListeners();
+ /*=============================*/
+
+ /*=============================*/
+ // Commands
+ commandManager = new CommandManager();
+ commandManager.registerCommands();
+ /*=============================*/
+
+ /*=============================*/
+ // Instantiating object tasks
+ Conquest.instate();
+ Faction.instate();
+ Kit.instate();
+ Koth.instate();
+ HCFProfile.instate();
+ ModItems.instate();
+ Mountain.instate();
+ Timer.instate();
+ /*=============================*/
+
+ /*=============================*/
+ // Loading Data
+ backend.loadConquests();
+ backend.loadKoths();
+ backend.loadMountains();
+ backend.loadFactions();
+
+ kitsFile.init();
+ locationsFile.init();
+ /*=============================*/
+
+ /*=============================*/
+ // Modules
+ moduleManager = new ModuleManager();
+ moduleManager.loadModules();
+ /*=============================*/
+ }
+
+ public void onDisable() {
+ if(moduleManager != null)
+ moduleManager.disableModules();
+
+ if(backend != null && backend.isLoaded()) {
+ HCFProfile.getProfiles().values().forEach(backend::saveProfileSync);
+ Faction.getFactions().values().forEach(backend::saveFactionSync);
+ Koth.getKoths().values().forEach(backend::saveKothSync);
+ Conquest.getConquests().values().forEach(backend::saveConquestSync);
+ Mountain.getMountains().values().forEach(backend::saveMountainSync);
+
+ backend.close();
+ }
+
+ if(boardManager != null)
+ boardManager.onDisable();
+
+ if(tablistManager != null)
+ tablistManager.onDisable();
+
+ reclaimFile.saveReclaimed();
+
+ PlayerLogger.despawnVillagers();
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/chat/ArrayWrapper.java b/src/main/java/me/hulipvp/hcf/api/chat/ArrayWrapper.java
new file mode 100644
index 0000000..0b80883
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/chat/ArrayWrapper.java
@@ -0,0 +1,111 @@
+package me.hulipvp.hcf.api.chat;
+
+import org.apache.commons.lang.Validate;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Represents a wrapper around an array class of an arbitrary reference type,
+ * which properly implements "value" hash code and equality functions.
+ *
+ * This class is intended for use as a key to a map.
+ *
+ *
+ * @param The type of elements in the array.
+ * @author Glen Husman
+ * @see Arrays
+ */
+public final class ArrayWrapper {
+
+ /**
+ * Creates an array wrapper with some elements.
+ *
+ * @param elements The elements of the array.
+ */
+ @SafeVarargs
+ public ArrayWrapper(E... elements) {
+ setArray(elements);
+ }
+
+ private E[] _array;
+
+ /**
+ * Retrieves a reference to the wrapped array instance.
+ *
+ * @return The array wrapped by this instance.
+ */
+ public E[] getArray() {
+ return _array;
+ }
+
+ /**
+ * Set this wrapper to wrap a punish array instance.
+ *
+ * @param array The punish wrapped array.
+ */
+ public void setArray(E[] array) {
+ Validate.notNull(array, "The array must not be null.");
+ _array = array;
+ }
+
+ /**
+ * Determines if this object has a value equivalent to another object.
+ *
+ * @see Arrays#equals(Object[], Object[])
+ */
+ @SuppressWarnings("rawtypes")
+ @Override
+ public boolean equals(Object other) {
+ if(!(other instanceof ArrayWrapper)) {
+ return false;
+ }
+ return Arrays.equals(_array, ((ArrayWrapper) other)._array);
+ }
+
+ /**
+ * Gets the hash code represented by this objects value.
+ *
+ * @return This object's hash code.
+ * @see Arrays#hashCode(Object[])
+ */
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(_array);
+ }
+
+ /**
+ * Converts an iterable element collection to an array of elements.
+ * The iteration order of the specified object will be used as the array element order.
+ *
+ * @param list The iterable of objects which will be converted to an array.
+ * @param c The type of the elements of the array.
+ * @return An array of elements in the specified iterable.
+ */
+ @SuppressWarnings("unchecked")
+ public static T[] toArray(Iterable extends T> list, Class c) {
+ int size = -1;
+ if(list instanceof Collection>) {
+ @SuppressWarnings("rawtypes") Collection coll = (Collection) list;
+ size = coll.size();
+ }
+
+
+ if(size < 0) {
+ size = 0;
+ // Ugly hack: Count it ourselves
+ for(@SuppressWarnings("unused") T element : list) {
+ size++;
+ }
+ }
+
+ T[] result = (T[]) Array.newInstance(c, size);
+ int i = 0;
+ for(T element : list) { // Assumes iteration order is consistent
+ result[i++] = element; // Assign array element at index THEN increment counter
+ }
+ return result;
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/chat/C.java b/src/main/java/me/hulipvp/hcf/api/chat/C.java
new file mode 100644
index 0000000..302a8ac
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/chat/C.java
@@ -0,0 +1,23 @@
+package me.hulipvp.hcf.api.chat;
+
+import org.bukkit.ChatColor;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class C {
+
+ public static String color(String input) {
+ return ChatColor.translateAlternateColorCodes('&', input);
+ }
+
+ public static String strip(String input) {
+ return ChatColor.stripColor(input);
+ }
+
+ public static List color(List input) {
+ return input.stream()
+ .map(C::color)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/chat/FancyMessage.java b/src/main/java/me/hulipvp/hcf/api/chat/FancyMessage.java
new file mode 100644
index 0000000..df1e8bb
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/chat/FancyMessage.java
@@ -0,0 +1,648 @@
+package me.hulipvp.hcf.api.chat;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.stream.JsonWriter;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.bukkit.configuration.serialization.ConfigurationSerialization;
+import org.bukkit.entity.Player;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.*;
+import java.util.logging.Level;
+
+/**
+ * Represents a formattable message. Such messages can use elements such as colors, formatting codes, hover and click backend, and other features provided by the vanilla Minecraft JSON message formatter .
+ * This class allows plugins to emulate the functionality of the vanilla Minecraft tellraw command .
+ *
+ * This class follows the builder pattern, allowing for method chaining.
+ * It is set up such that invocations of property-setting methods will affect the current kits component,
+ * and a call to {@link #then()} or {@link #then(String)} will append a punish kits component to the end of the message,
+ * optionally initializing it with text. Further property-setting method calls will affect that kits component.
+ *
+ */
+public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable, ConfigurationSerializable {
+
+ static {
+ ConfigurationSerialization.registerClass(FancyMessage.class);
+ }
+
+ private List messageParts;
+ private String jsonString;
+ private boolean dirty;
+
+ @Override
+ public FancyMessage clone() throws CloneNotSupportedException {
+ FancyMessage instance = (FancyMessage) super.clone();
+ instance.messageParts = new ArrayList(messageParts.size());
+ for(int i = 0; i < messageParts.size(); i++) {
+ instance.messageParts.add(i, messageParts.get(i).clone());
+ }
+ instance.dirty = false;
+ instance.jsonString = null;
+ return instance;
+ }
+
+ /**
+ * Creates a JSON message with text.
+ *
+ * @param firstPartText The existing text in the message.
+ */
+ public FancyMessage(final String firstPartText) {
+ this(TextualComponent.rawText(firstPartText));
+ }
+
+ public FancyMessage(final TextualComponent firstPartText) {
+ messageParts = new ArrayList();
+ messageParts.add(new MessagePart(firstPartText));
+ jsonString = null;
+ dirty = false;
+ }
+
+ /**
+ * Creates a JSON message without text.
+ */
+ public FancyMessage() {
+ this((TextualComponent) null);
+ }
+
+ /**
+ * Sets the text of the current kits component to a value.
+ *
+ * @param text The punish text of the current kits component.
+ * @return This builder instance.
+ */
+ public FancyMessage text(String text) {
+ MessagePart latest = latest();
+ latest.text = TextualComponent.rawText(text);
+ dirty = true;
+ return this;
+ }
+
+ /**
+ * Sets the text of the current kits component to a value.
+ *
+ * @param text The punish text of the current kits component.
+ * @return This builder instance.
+ */
+ public FancyMessage text(TextualComponent text) {
+ MessagePart latest = latest();
+ latest.text = text;
+ dirty = true;
+ return this;
+ }
+
+ /**
+ * Sets the color of the current kits component to a value.
+ *
+ * @param color The punish color of the current kits component.
+ * @return This builder instance.
+ * @throws IllegalArgumentException If the specified {@code ChatColor} enumeration value is not a color (but a format value).
+ */
+ public FancyMessage color(final ChatColor color) {
+ if(!color.isColor()) {
+ throw new IllegalArgumentException(color.name() + " is not a color");
+ }
+ latest().color = color;
+ dirty = true;
+ return this;
+ }
+
+ /**
+ * Sets the stylization of the current kits component.
+ *
+ * @param styles The array of styles to apply to the kits component.
+ * @return This builder instance.
+ * @throws IllegalArgumentException If any of the enumeration values in the array do not represent formatters.
+ */
+ public FancyMessage style(ChatColor... styles) {
+ for(final ChatColor style : styles) {
+ if(!style.isFormat()) {
+ throw new IllegalArgumentException(style.name() + " is not a style");
+ }
+ }
+ latest().styles.addAll(Arrays.asList(styles));
+ dirty = true;
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to instruct the client to open a file on the client side filesystem when the currently edited part of the {@code FancyMessage} is clicked.
+ *
+ * @param path The path of the file on the client filesystem.
+ * @return This builder instance.
+ */
+ public FancyMessage file(final String path) {
+ onClick("open_file", path);
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to instruct the client to open a webpage in the client's web browser when the currently edited part of the {@code FancyMessage} is clicked.
+ *
+ * @param url The URL of the page to open when the link is clicked.
+ * @return This builder instance.
+ */
+ public FancyMessage link(final String url) {
+ onClick("open_url", url);
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to instruct the client to replace the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is clicked.
+ * The client will not immediately send the command to the server to be executed unless the client profiles submits the command/chat message, usually with the enter key.
+ *
+ * @param command The text to display in the chat bar of the client.
+ * @return This builder instance.
+ */
+ public FancyMessage suggest(final String command) {
+ onClick("suggest_command", command);
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to instruct the client to append the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is SHIFT-CLICKED.
+ * The client will not immediately send the command to the server to be executed unless the client profiles submits the command/chat message, usually with the enter key.
+ *
+ * @param command The text to append to the chat bar of the client.
+ * @return This builder instance.
+ */
+ public FancyMessage insert(final String command) {
+ latest().insertionData = command;
+ dirty = true;
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to instruct the client to send the specified string to the server as a chat message when the currently edited part of the {@code FancyMessage} is clicked.
+ * The client will immediately send the command to the server to be executed when the kits component is clicked.
+ *
+ * @param command The text to display in the chat bar of the client.
+ * @return This builder instance.
+ */
+ public FancyMessage command(final String command) {
+ onClick("run_command", command);
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to display information about an achievement when the client hovers over the text.
+ * Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.
+ *
+ * @param name The name of the achievement to display, excluding the "achievement." prefix.
+ * @return This builder instance.
+ */
+ public FancyMessage achievementTooltip(final String name) {
+ onHover("show_achievement", new JsonString("achievement." + name));
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to display raw text when the client hovers over the text.
+ * Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.
+ *
+ * @param text The text, which supports newlines, which will be displayed to the client upon hovering.
+ * @return This builder instance.
+ */
+ public FancyMessage tooltip(final String text) {
+ onHover("show_text", new JsonString(text));
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to display raw text when the client hovers over the text.
+ * Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.
+ *
+ * @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created.
+ * @return This builder instance.
+ */
+ public FancyMessage tooltip(final Iterable lines) {
+ tooltip(ArrayWrapper.toArray(lines, String.class));
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to display raw text when the client hovers over the text.
+ * Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.
+ *
+ * @param lines The lines of text which will be displayed to the client upon hovering.
+ * @return This builder instance.
+ */
+ public FancyMessage tooltip(final String... lines) {
+ StringBuilder builder = new StringBuilder();
+ for(int i = 0; i < lines.length; i++) {
+ builder.append(lines[i]);
+ if(i != lines.length - 1) {
+ builder.append('\n');
+ }
+ }
+ tooltip(builder.toString());
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to display formatted text when the client hovers over the text.
+ * Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.
+ *
+ * @param text The formatted text which will be displayed to the client upon hovering.
+ * @return This builder instance.
+ */
+ public FancyMessage formattedTooltip(FancyMessage text) {
+ for(MessagePart component : text.messageParts) {
+ if(component.clickActionData != null && component.clickActionName != null) {
+ throw new IllegalArgumentException("The tooltip text cannot have click backend.");
+ } else if(component.hoverActionData != null && component.hoverActionName != null) {
+ throw new IllegalArgumentException("The tooltip text cannot have a tooltip.");
+ }
+ }
+ onHover("show_text", text);
+ return this;
+ }
+
+ /**
+ * Set the behavior of the current kits component to display the specified lines of formatted text when the client hovers over the text.
+ * Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.
+ *
+ * @param lines The lines of formatted text which will be displayed to the client upon hovering.
+ * @return This builder instance.
+ */
+ public FancyMessage formattedTooltip(FancyMessage... lines) {
+ if(lines.length < 1) {
+ onHover(null, null); // Clear tooltip
+ return this;
+ }
+
+ FancyMessage result = new FancyMessage();
+ result.messageParts.clear(); // Remove the one existing text component that exists by default, which destabilizes the object
+
+ for(int i = 0; i < lines.length; i++) {
+ try {
+ for(MessagePart component : lines[i]) {
+ if(component.clickActionData != null && component.clickActionName != null) {
+ throw new IllegalArgumentException("The tooltip text cannot have click backend.");
+ } else if(component.hoverActionData != null && component.hoverActionName != null) {
+ throw new IllegalArgumentException("The tooltip text cannot have a tooltip.");
+ }
+ if(component.hasText()) {
+ result.messageParts.add(component.clone());
+ }
+ }
+ if(i != lines.length - 1) {
+ result.messageParts.add(new MessagePart(TextualComponent.rawText("\n")));
+ }
+ } catch(CloneNotSupportedException e) {
+ Bukkit.getLogger().log(Level.WARNING, "Failed to clone object", e);
+ return this;
+ }
+ }
+ return formattedTooltip(result.messageParts.isEmpty() ? null : result); // Throws NPE if size is 0, intended
+ }
+
+ /**
+ * Set the behavior of the current kits component to display the specified lines of formatted text when the client hovers over the text.
+ * Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.
+ *
+ * @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created.
+ * @return This builder instance.
+ */
+ public FancyMessage formattedTooltip(final Iterable lines) {
+ return formattedTooltip(ArrayWrapper.toArray(lines, FancyMessage.class));
+ }
+
+ /**
+ * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
+ *
+ * @param replacements The replacements, in order, that will be used in the language-specific message.
+ * @return This builder instance.
+ */
+ public FancyMessage translationReplacements(final String... replacements) {
+ for(String str : replacements) {
+ latest().translationReplacements.add(new JsonString(str));
+ }
+ dirty = true;
+
+ return this;
+ }
+ /*
+
+ /**
+ * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
+ * @param replacements The replacements, in order, that will be used in the language-specific message.
+ * @return This builder instance.
+ */ /* ------------
+ public FancyMessage translationReplacements(final Iterable extends CharSequence> replacements){
+ for (CharSequence str : replacements){
+ latest().translationReplacements.add(punish JsonString(str));
+ }
+
+ return this;
+ }
+
+ */
+
+ /**
+ * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
+ *
+ * @param replacements The replacements, in order, that will be used in the language-specific message.
+ * @return This builder instance.
+ */
+ public FancyMessage translationReplacements(final FancyMessage... replacements) {
+ for(FancyMessage str : replacements) {
+ latest().translationReplacements.add(str);
+ }
+
+ dirty = true;
+
+ return this;
+ }
+
+ /**
+ * If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
+ *
+ * @param replacements The replacements, in order, that will be used in the language-specific message.
+ * @return This builder instance.
+ */
+ public FancyMessage translationReplacements(final Iterable replacements) {
+ return translationReplacements(ArrayWrapper.toArray(replacements, FancyMessage.class));
+ }
+
+ /**
+ * Terminate construction of the current kits component, and begin construction of a punish message component.
+ * After a successful call to this method, all setter methods will refer to a punish message component, created as a result of the call to this method.
+ *
+ * @param text The text which will populate the punish message component.
+ * @return This builder instance.
+ */
+ public FancyMessage then(final String text) {
+ return then(TextualComponent.rawText(text));
+ }
+
+ /**
+ * Terminate construction of the current kits component, and begin construction of a punish message component.
+ * After a successful call to this method, all setter methods will refer to a punish message component, created as a result of the call to this method.
+ *
+ * @param text The text which will populate the punish message component.
+ * @return This builder instance.
+ */
+ public FancyMessage then(final TextualComponent text) {
+ if(!latest().hasText()) {
+ throw new IllegalStateException("previous message part has no text");
+ }
+ messageParts.add(new MessagePart(text));
+ dirty = true;
+ return this;
+ }
+
+ /**
+ * Terminate construction of the current kits component, and begin construction of a punish message component.
+ * After a successful call to this method, all setter methods will refer to a punish message component, created as a result of the call to this method.
+ *
+ * @return This builder instance.
+ */
+ public FancyMessage then() {
+ if(!latest().hasText())
+ throw new IllegalStateException("previous message part has no text");
+
+ messageParts.add(new MessagePart());
+ dirty = true;
+ return this;
+ }
+
+ @Override
+ public void writeJson(JsonWriter writer) throws IOException {
+ if(messageParts.size() == 1) {
+ latest().writeJson(writer);
+ } else {
+ writer.beginObject().name("text").value("").name("me/hulipvp/hcf/api/chat").beginArray();
+ for(final MessagePart part : this) {
+ part.writeJson(writer);
+ }
+ writer.endArray().endObject();
+ }
+ }
+
+ /**
+ * Serialize this fancy message, converting it into syntactically-valid JSON using a {@link JsonWriter}.
+ * This JSON should be compatible with vanilla formatter commands such as {@code /tellraw}.
+ *
+ * @return The JSON string representing this object.
+ */
+ public String toJSONString() {
+ if(!dirty && jsonString != null) {
+ return jsonString;
+ }
+ StringWriter string = new StringWriter();
+ JsonWriter json = new JsonWriter(string);
+ try {
+ writeJson(json);
+ json.close();
+ } catch(IOException e) {
+ throw new RuntimeException("invalid message");
+ }
+ jsonString = string.toString();
+ dirty = false;
+ return jsonString;
+ }
+
+ /**
+ * Sends this message to a profiles. The profiles will receive the fully-fledged formatted display of this message.
+ *
+ * @param player The profiles who will receive the message.
+ */
+ public void send(Player player) {
+ send(player, toJSONString());
+ }
+
+ private void send(CommandSender sender, String jsonString) {
+ if(!(sender instanceof Player)) {
+ sender.sendMessage(toOldMessageFormat());
+ return;
+ }
+ Player player = (Player) sender;
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + player.getName() + " " + jsonString);
+ }
+
+ /**
+ * Sends this message to a command sender.
+ * If the sender is a profiles, they will receive the fully-fledged formatted display of this message.
+ * Otherwise, they will receive a version of this message with less formatting.
+ *
+ * @param sender The command sender who will receive the message.
+ * @see #toOldMessageFormat()
+ */
+ public void send(CommandSender sender) {
+ send(sender, toJSONString());
+ }
+
+ /**
+ * Sends this message to multiple command senders.
+ *
+ * @param senders The command senders who will receive the message.
+ * @see #send(CommandSender)
+ */
+ public void send(final Iterable extends CommandSender> senders) {
+ String string = toJSONString();
+ for(final CommandSender sender : senders) {
+ send(sender, string);
+ }
+ }
+
+ /**
+ * Convert this message to a human-readable string with limited formatting.
+ * This method is used to send this message to clients without JSON formatting support.
+ *
+ * Serialization of this message by using this message will include (in this order for each message part):
+ *
+ * The color of each message part.
+ * The applicable stylizations for each message part.
+ * The core text of the message part.
+ *
+ * The primary omissions are tooltips and clickable actions. Consequently, this method should be used only as a last resort.
+ *
+ *
+ * Color and formatting can be removed from the returned string by using {@link ChatColor#stripColor(String)}.
+ *
+ * @return A human-readable string representing limited formatting in addition to the core text of this message.
+ */
+ public String toOldMessageFormat() {
+ StringBuilder result = new StringBuilder();
+ for(MessagePart part : this) {
+ result.append(part.color == null ? "" : part.color);
+ for(ChatColor formatSpecifier : part.styles) {
+ result.append(formatSpecifier);
+ }
+ result.append(part.text);
+ }
+ return result.toString();
+ }
+
+ private MessagePart latest() {
+ return messageParts.get(messageParts.size() - 1);
+ }
+
+ private void onClick(final String name, final String data) {
+ final MessagePart latest = latest();
+ latest.clickActionName = name;
+ latest.clickActionData = data;
+ dirty = true;
+ }
+
+ private void onHover(final String name, final JsonRepresentedObject data) {
+ final MessagePart latest = latest();
+ latest.hoverActionName = name;
+ latest.hoverActionData = data;
+ dirty = true;
+ }
+
+ // Doc copied from interface
+ public Map serialize() {
+ HashMap map = new HashMap();
+ map.put("messageParts", messageParts);
+ // map.put("JSON", toJSONString());
+ return map;
+ }
+
+ /**
+ * Deserializes a JSON-represented message from a mapping of key-value pairs.
+ * This is called by the Bukkit serialization API.
+ * It is not intended for direct public API consumption.
+ *
+ * @param serialized The key-value mapping which represents a fancy message.
+ */
+ @SuppressWarnings("unchecked")
+ public static FancyMessage deserialize(Map serialized) {
+ FancyMessage msg = new FancyMessage();
+ msg.messageParts = (List) serialized.get("messageParts");
+ msg.jsonString = serialized.containsKey("JSON") ? serialized.get("JSON").toString() : null;
+ msg.dirty = !serialized.containsKey("JSON");
+ return msg;
+ }
+
+ /**
+ * Internally called method. Not for API consumption.
+ */
+ public Iterator iterator() {
+ return messageParts.iterator();
+ }
+
+ private static JsonParser _stringParser = new JsonParser();
+
+ /**
+ * Deserializes a fancy message from its JSON representation. This JSON representation is of the format of
+ * that returned by {@link #toJSONString()}, and is compatible with vanilla inputs.
+ *
+ * @param json The JSON string which represents a fancy message.
+ * @return A {@code FancyMessage} representing the parameterized JSON message.
+ */
+ public static FancyMessage deserialize(String json) {
+ JsonObject serialized = _stringParser.parse(json).getAsJsonObject();
+ JsonArray extra = serialized.getAsJsonArray("me/hulipvp/hcf/api/chat"); // Get the utils component
+ FancyMessage returnVal = new FancyMessage();
+ returnVal.messageParts.clear();
+ for(JsonElement mPrt : extra) {
+ MessagePart component = new MessagePart();
+ JsonObject messagePart = mPrt.getAsJsonObject();
+ for(Map.Entry entry : messagePart.entrySet()) {
+ // Deserialize text
+ if(TextualComponent.isTextKey(entry.getKey())) {
+ // The map mimics the YAML serialization, which has a "key" field and one or more "value" fields
+ Map serializedMapForm = new HashMap(); // Must be object due to Bukkit serializer API compliance
+ serializedMapForm.put("key", entry.getKey());
+ if(entry.getValue().isJsonPrimitive()) {
+ // Assume string
+ serializedMapForm.put("value", entry.getValue().getAsString());
+ } else {
+ // Composite object, but we assume each element is a string
+ for(Map.Entry compositeNestedElement : entry.getValue().getAsJsonObject().entrySet()) {
+ serializedMapForm.put("value." + compositeNestedElement.getKey(), compositeNestedElement.getValue().getAsString());
+ }
+ }
+ component.text = TextualComponent.deserialize(serializedMapForm);
+ } else if(MessagePart.stylesToNames.inverse().containsKey(entry.getKey())) {
+ if(entry.getValue().getAsBoolean()) {
+ component.styles.add(MessagePart.stylesToNames.inverse().get(entry.getKey()));
+ }
+ } else if(entry.getKey().equals("color")) {
+ component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase());
+ } else if(entry.getKey().equals("clickEvent")) {
+ JsonObject object = entry.getValue().getAsJsonObject();
+ component.clickActionName = object.get("action").getAsString();
+ component.clickActionData = object.get("value").getAsString();
+ } else if(entry.getKey().equals("hoverEvent")) {
+ JsonObject object = entry.getValue().getAsJsonObject();
+ component.hoverActionName = object.get("action").getAsString();
+ if(object.get("value").isJsonPrimitive()) {
+ // Assume string
+ component.hoverActionData = new JsonString(object.get("value").getAsString());
+ } else {
+ // Assume composite type
+ // The only composite type we currently store is another FancyMessage
+ // Therefore, recursion time!
+ component.hoverActionData = deserialize(object.get("value").toString() /* This should properly serialize the JSON object as a JSON string */);
+ }
+ } else if(entry.getKey().equals("insertion")) {
+ component.insertionData = entry.getValue().getAsString();
+ } else if(entry.getKey().equals("with")) {
+ for(JsonElement object : entry.getValue().getAsJsonArray()) {
+ if(object.isJsonPrimitive()) {
+ component.translationReplacements.add(new JsonString(object.getAsString()));
+ } else {
+ // Only composite type stored in this array is - again - FancyMessages
+ // Recurse within this function to parse this as a translation replacement
+ component.translationReplacements.add(deserialize(object.toString()));
+ }
+ }
+ }
+ }
+ returnVal.messageParts.add(component);
+ }
+ return returnVal;
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/chat/JsonRepresentedObject.java b/src/main/java/me/hulipvp/hcf/api/chat/JsonRepresentedObject.java
new file mode 100644
index 0000000..c80264e
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/chat/JsonRepresentedObject.java
@@ -0,0 +1,20 @@
+package me.hulipvp.hcf.api.chat;
+
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+
+/**
+ * Represents an object that can be serialized to a JSON writer instance.
+ */
+interface JsonRepresentedObject {
+
+ /**
+ * Writes the JSON representation of this object to the specified writer.
+ *
+ * @param writer The JSON writer which will receive the object.
+ * @throws IOException If an error occurs writing to the stream.
+ */
+ void writeJson(JsonWriter writer) throws IOException;
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/chat/JsonString.java b/src/main/java/me/hulipvp/hcf/api/chat/JsonString.java
new file mode 100644
index 0000000..acd84a7
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/chat/JsonString.java
@@ -0,0 +1,47 @@
+package me.hulipvp.hcf.api.chat;
+
+import com.google.gson.stream.JsonWriter;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a JSON string value.
+ * Writes by this object will not write name values nor begin/end objects in the JSON stream.
+ * All writes merely write the represented string value.
+ */
+final class JsonString implements JsonRepresentedObject, ConfigurationSerializable {
+
+ private String _value;
+
+ public JsonString(CharSequence value) {
+ _value = value == null ? null : value.toString();
+ }
+
+ @Override
+ public void writeJson(JsonWriter writer) throws IOException {
+ writer.value(getValue());
+ }
+
+ public String getValue() {
+ return _value;
+ }
+
+ public Map serialize() {
+ HashMap theSingleValue = new HashMap();
+ theSingleValue.put("stringValue", _value);
+ return theSingleValue;
+ }
+
+ public static JsonString deserialize(Map map) {
+ return new JsonString(map.get("stringValue").toString());
+ }
+
+ @Override
+ public String toString() {
+ return _value;
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/chat/MessagePart.java b/src/main/java/me/hulipvp/hcf/api/chat/MessagePart.java
new file mode 100644
index 0000000..78619e4
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/chat/MessagePart.java
@@ -0,0 +1,148 @@
+package me.hulipvp.hcf.api.chat;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.gson.stream.JsonWriter;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.bukkit.configuration.serialization.ConfigurationSerialization;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+
+/**
+ * Internal class: Represents a component of a JSON-serializable {@link FancyMessage}.
+ */
+final class MessagePart implements JsonRepresentedObject, ConfigurationSerializable, Cloneable {
+
+ ChatColor color = ChatColor.WHITE;
+ ArrayList styles = new ArrayList();
+ String clickActionName = null, clickActionData = null, hoverActionName = null;
+ JsonRepresentedObject hoverActionData = null;
+ TextualComponent text = null;
+ String insertionData = null;
+ ArrayList translationReplacements = new ArrayList();
+
+ MessagePart(final TextualComponent text) {
+ this.text = text;
+ }
+
+ MessagePart() {
+ this.text = null;
+ }
+
+ boolean hasText() {
+ return text != null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public MessagePart clone() throws CloneNotSupportedException {
+ MessagePart obj = (MessagePart) super.clone();
+ obj.styles = (ArrayList) styles.clone();
+ if(hoverActionData instanceof JsonString) {
+ obj.hoverActionData = new JsonString(((JsonString) hoverActionData).getValue());
+ } else if(hoverActionData instanceof FancyMessage) {
+ obj.hoverActionData = ((FancyMessage) hoverActionData).clone();
+ }
+ obj.translationReplacements = (ArrayList) translationReplacements.clone();
+ return obj;
+
+ }
+
+ static final BiMap stylesToNames;
+
+ static {
+ ImmutableBiMap.Builder builder = ImmutableBiMap.builder();
+ for(final ChatColor style : ChatColor.values()) {
+ if(!style.isFormat()) {
+ continue;
+ }
+
+ String styleName;
+ switch(style) {
+ case MAGIC:
+ styleName = "obfuscated";
+ break;
+ case UNDERLINE:
+ styleName = "underlined";
+ break;
+ default:
+ styleName = style.name().toLowerCase();
+ break;
+ }
+
+ builder.put(style, styleName);
+ }
+ stylesToNames = builder.build();
+ }
+
+ public void writeJson(JsonWriter json) {
+ try {
+ json.beginObject();
+ text.writeJson(json);
+ json.name("color").value(color.name().toLowerCase());
+ for(final ChatColor style : styles) {
+ json.name(stylesToNames.get(style)).value(true);
+ }
+ if(clickActionName != null && clickActionData != null) {
+ json.name("clickEvent").beginObject().name("action").value(clickActionName).name("value").value(clickActionData).endObject();
+ }
+ if(hoverActionName != null && hoverActionData != null) {
+ json.name("hoverEvent").beginObject().name("action").value(hoverActionName).name("value");
+ hoverActionData.writeJson(json);
+ json.endObject();
+ }
+ if(insertionData != null) {
+ json.name("insertion").value(insertionData);
+ }
+ if(translationReplacements.size() > 0 && text != null && TextualComponent.isTranslatableText(text)) {
+ json.name("with").beginArray();
+ for(JsonRepresentedObject obj : translationReplacements) {
+ obj.writeJson(json);
+ }
+ json.endArray();
+ }
+ json.endObject();
+ } catch(IOException e) {
+ Bukkit.getLogger().log(Level.WARNING, "A problem occured during writing of JSON string", e);
+ }
+ }
+
+ public Map serialize() {
+ HashMap map = new HashMap();
+ map.put("text", text);
+ map.put("styles", styles);
+ map.put("color", color.getChar());
+ map.put("hoverActionName", hoverActionName);
+ map.put("hoverActionData", hoverActionData);
+ map.put("clickActionName", clickActionName);
+ map.put("clickActionData", clickActionData);
+ map.put("insertion", insertionData);
+ map.put("translationReplacements", translationReplacements);
+ return map;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static MessagePart deserialize(Map serialized) {
+ MessagePart part = new MessagePart((TextualComponent) serialized.get("text"));
+ part.styles = (ArrayList) serialized.get("styles");
+ part.color = ChatColor.getByChar(serialized.get("color").toString());
+ part.hoverActionName = (String) serialized.get("hoverActionName");
+ part.hoverActionData = (JsonRepresentedObject) serialized.get("hoverActionData");
+ part.clickActionName = (String) serialized.get("clickActionName");
+ part.clickActionData = (String) serialized.get("clickActionData");
+ part.insertionData = (String) serialized.get("insertion");
+ part.translationReplacements = (ArrayList) serialized.get("translationReplacements");
+ return part;
+ }
+
+ static {
+ ConfigurationSerialization.registerClass(MessagePart.class);
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/chat/TextualComponent.java b/src/main/java/me/hulipvp/hcf/api/chat/TextualComponent.java
new file mode 100644
index 0000000..dba7d3f
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/chat/TextualComponent.java
@@ -0,0 +1,294 @@
+package me.hulipvp.hcf.api.chat;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.gson.stream.JsonWriter;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.bukkit.configuration.serialization.ConfigurationSerialization;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a textual component of a message part.
+ * This can be used to not only represent string literals in a JSON message,
+ * but also to represent localized strings and other text values.
+ * Different instances of this class can be created with static constructor methods.
+ */
+public abstract class TextualComponent implements Cloneable {
+
+ static {
+ ConfigurationSerialization.registerClass(ArbitraryTextTypeComponent.class);
+ ConfigurationSerialization.registerClass(ComplexTextTypeComponent.class);
+ }
+
+ @Override
+ public String toString() {
+ return getReadableString();
+ }
+
+ /**
+ * @return The JSON key used to represent text components of this type.
+ */
+ public abstract String getKey();
+
+ /**
+ * @return A readable String
+ */
+ public abstract String getReadableString();
+
+ /**
+ * Clones a textual component instance.
+ * The returned object should not reference this textual component instance, but should maintain the same key and value.
+ */
+ @Override
+ public abstract TextualComponent clone() throws CloneNotSupportedException;
+
+ /**
+ * Writes the text backend represented by this textual component to the specified JSON writer object.
+ * A punish object within the writer is not started.
+ *
+ * @param writer The object to which to write the JSON backend.
+ * @throws IOException If an error occurs while writing to the stream.
+ */
+ public abstract void writeJson(JsonWriter writer) throws IOException;
+
+ static TextualComponent deserialize(Map map) {
+ if(map.containsKey("key") && map.size() == 2 && map.containsKey("value")) {
+ // Arbitrary text component
+ return ArbitraryTextTypeComponent.deserialize(map);
+ } else if(map.size() >= 2 && map.containsKey("key") && !map.containsKey("value") /* It contains keys that START WITH value */) {
+ // Complex JSON object
+ return ComplexTextTypeComponent.deserialize(map);
+ }
+
+ return null;
+ }
+
+ static boolean isTextKey(String key) {
+ return key.equals("translate") || key.equals("text") || key.equals("score") || key.equals("selector");
+ }
+
+ static boolean isTranslatableText(TextualComponent component) {
+ return component instanceof ComplexTextTypeComponent && ((ComplexTextTypeComponent) component).getKey().equals("translate");
+ }
+
+ /**
+ * Internal class used to represent all types of text components.
+ * Exception validating done is on keys and values.
+ */
+ private static final class ArbitraryTextTypeComponent extends TextualComponent implements ConfigurationSerializable {
+
+ public ArbitraryTextTypeComponent(String key, String value) {
+ setKey(key);
+ setValue(value);
+ }
+
+ @Override
+ public String getKey() {
+ return _key;
+ }
+
+ public void setKey(String key) {
+ Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
+ _key = key;
+ }
+
+ public String getValue() {
+ return _value;
+ }
+
+ public void setValue(String value) {
+ Preconditions.checkArgument(value != null, "The value must be specified.");
+ _value = value;
+ }
+
+ private String _key;
+ private String _value;
+
+ @Override
+ public TextualComponent clone() throws CloneNotSupportedException {
+ // Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone
+ return new ArbitraryTextTypeComponent(getKey(), getValue());
+ }
+
+ @Override
+ public void writeJson(JsonWriter writer) throws IOException {
+ writer.name(getKey()).value(getValue());
+ }
+
+ @SuppressWarnings("serial")
+ public Map serialize() {
+ return new HashMap() {{
+ put("key", getKey());
+ put("value", getValue());
+ }};
+ }
+
+ public static ArbitraryTextTypeComponent deserialize(Map map) {
+ return new ArbitraryTextTypeComponent(map.get("key").toString(), map.get("value").toString());
+ }
+
+ @Override
+ public String getReadableString() {
+ return getValue();
+ }
+ }
+
+ /**
+ * Internal class used to represent a text component with a nested JSON value.
+ * Exception validating done is on keys and values.
+ */
+ private static final class ComplexTextTypeComponent extends TextualComponent implements ConfigurationSerializable {
+
+ public ComplexTextTypeComponent(String key, Map values) {
+ setKey(key);
+ setValue(values);
+ }
+
+ @Override
+ public String getKey() {
+ return _key;
+ }
+
+ public void setKey(String key) {
+ Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
+ _key = key;
+ }
+
+ public Map getValue() {
+ return _value;
+ }
+
+ public void setValue(Map value) {
+ Preconditions.checkArgument(value != null, "The value must be specified.");
+ _value = value;
+ }
+
+ private String _key;
+ private Map _value;
+
+ @Override
+ public TextualComponent clone() throws CloneNotSupportedException {
+ // Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone
+ return new ComplexTextTypeComponent(getKey(), getValue());
+ }
+
+ @Override
+ public void writeJson(JsonWriter writer) throws IOException {
+ writer.name(getKey());
+ writer.beginObject();
+ for(Map.Entry jsonPair : _value.entrySet()) {
+ writer.name(jsonPair.getKey()).value(jsonPair.getValue());
+ }
+ writer.endObject();
+ }
+
+ @SuppressWarnings("serial")
+ public Map serialize() {
+ return new HashMap() {{
+ put("key", getKey());
+ for(Entry valEntry : getValue().entrySet()) {
+ put("value." + valEntry.getKey(), valEntry.getValue());
+ }
+ }};
+ }
+
+ public static ComplexTextTypeComponent deserialize(Map map) {
+ String key = null;
+ Map value = new HashMap();
+ for(Map.Entry valEntry : map.entrySet()) {
+ if(valEntry.getKey().equals("key")) {
+ key = (String) valEntry.getValue();
+ } else if(valEntry.getKey().startsWith("value.")) {
+ value.put(((String) valEntry.getKey()).substring(6) /* Strips out the value prefix */, valEntry.getValue().toString());
+ }
+ }
+ return new ComplexTextTypeComponent(key, value);
+ }
+
+ @Override
+ public String getReadableString() {
+ return getKey();
+ }
+ }
+
+ /**
+ * Create a textual component representing a string literal.
+ * This is the default type of textual component when a single string literal is given to a method.
+ *
+ * @param textValue The text which will be represented.
+ * @return The text component representing the specified literal text.
+ */
+ public static TextualComponent rawText(String textValue) {
+ return new ArbitraryTextTypeComponent("text", textValue);
+ }
+
+
+ /**
+ * Create a textual component representing a localized string.
+ * The client will see this text component as their localized version of the specified string key , which can be overridden by a resource pack.
+ *
+ * If the specified translation key is not present on the client resource pack, the translation key will be displayed as a string literal to the client.
+ *
+ *
+ * @param translateKey The string key which maps to localized text.
+ * @return The text component representing the specified localized text.
+ */
+ public static TextualComponent localizedText(String translateKey) {
+ return new ArbitraryTextTypeComponent("translate", translateKey);
+ }
+
+ private static void throwUnsupportedSnapshot() {
+ throw new UnsupportedOperationException("This feature is only supported in snapshot releases.");
+ }
+
+ /**
+ * Create a textual component representing a me.joeleoli.practice.board value.
+ * The client will see their own score for the specified objective as the text represented by this component.
+ *
+ * This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.
+ *
+ *
+ * @param scoreboardObjective The name of the objective for which to display the score.
+ * @return The text component representing the specified me.joeleoli.practice.board score (for the viewing profiles), or {@code null} if an error occurs during JSON serialization.
+ */
+ public static TextualComponent objectiveScore(String scoreboardObjective) {
+ return objectiveScore("*", scoreboardObjective);
+ }
+
+ /**
+ * Create a textual component representing a me.joeleoli.practice.board value.
+ * The client will see the score of the specified profiles for the specified objective as the text represented by this component.
+ *
+ * This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.
+ *
+ *
+ * @param playerName The name of the profiles whos score will be shown. If this string represents the single-character sequence "*", the viewing profiles's score will be displayed.
+ * Standard minecraft selectors (@a, @p, etc) are not supported.
+ * @param scoreboardObjective The name of the objective for which to display the score.
+ * @return The text component representing the specified me.joeleoli.practice.board score for the specified profiles, or {@code null} if an error occurs during JSON serialization.
+ */
+ public static TextualComponent objectiveScore(String playerName, String scoreboardObjective) {
+ throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE OVERLOADS documentation accordingly
+
+ return new ComplexTextTypeComponent("score", ImmutableMap.builder().put("name", playerName).put("objective", scoreboardObjective).build());
+ }
+
+ /**
+ * Create a textual component representing a profiles name, retrievable by using a standard minecraft selector.
+ * The client will see the players or entities captured by the specified selector as the text represented by this component.
+ *
+ * This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.
+ *
+ *
+ * @param selector The minecraft profiles or entity selector which will capture the entities whose string representations will be displayed in the place of this text component.
+ * @return The text component representing the name of the entities captured by the selector.
+ */
+ public static TextualComponent selector(String selector) {
+ throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE OVERLOADS documentation accordingly
+
+ return new ArbitraryTextTypeComponent("selector", selector);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/command/BukkitCommand.java b/src/main/java/me/hulipvp/hcf/api/command/BukkitCommand.java
new file mode 100644
index 0000000..221e1b9
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/command/BukkitCommand.java
@@ -0,0 +1,75 @@
+package me.hulipvp.hcf.api.command;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.command.CommandException;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+import org.bukkit.plugin.Plugin;
+
+import java.util.List;
+
+public class BukkitCommand extends org.bukkit.command.Command {
+ private final Plugin owningPlugin;
+ private CommandExecutor executor;
+ protected BukkitCompleter completer;
+
+ protected BukkitCommand(String label, CommandExecutor executor, Plugin owner) {
+ super(label);
+ this.executor = executor;
+ this.owningPlugin = owner;
+ this.usageMessage = "";
+ }
+
+ @Override
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
+ if(!this.owningPlugin.isEnabled())
+ return false;
+ if(!testPermission(sender))
+ return true;
+ boolean success;
+
+ try {
+ success = this.executor.onCommand(sender, this, commandLabel, args);
+ } catch(Throwable ex) {
+ throw new CommandException("Unhandled exception executing command '" + commandLabel + "' in plugin " + this.owningPlugin.getDescription().getFullName(), ex);
+ }
+
+ if(!success && this.usageMessage.length() > 0) {
+ for(String line : this.usageMessage.replace("", commandLabel).split("\n")) {
+ sender.sendMessage(line);
+ }
+ }
+
+ return success;
+ }
+
+ @Override
+ public List tabComplete(CommandSender sender, String alias, String[] args) throws CommandException, IllegalArgumentException {
+ Validate.notNull(sender, "Sender cannot be null");
+ Validate.notNull(args, "Arguments cannot be null");
+ Validate.notNull(alias, "Alias cannot be null");
+
+ List completions = null;
+
+ try {
+ if(this.completer != null)
+ completions = this.completer.onTabComplete(sender, this, alias, args);
+ if(completions == null && this.executor instanceof TabCompleter)
+ completions = ((TabCompleter) this.executor).onTabComplete(sender, this, alias, args);
+ } catch(Throwable ex) {
+ StringBuilder message = new StringBuilder();
+ message.append("Unhandled exception during tab completion for command '/").append(alias).append(' ');
+ for(String arg : args)
+ message.append(arg).append(' ');
+ message.deleteCharAt(message.length() - 1).append("' in plugin ").append(this.owningPlugin.getDescription().getFullName());
+ throw new CommandException(message.toString(), ex);
+ }
+
+ if(completions == null)
+ return super.tabComplete(sender, alias, args);
+
+ return completions;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/api/command/BukkitCompleter.java b/src/main/java/me/hulipvp/hcf/api/command/BukkitCompleter.java
new file mode 100644
index 0000000..be26c25
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/command/BukkitCompleter.java
@@ -0,0 +1,51 @@
+package me.hulipvp.hcf.api.command;
+
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.TabCompleter;
+
+import java.lang.reflect.Method;
+import java.util.AbstractMap;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class BukkitCompleter implements TabCompleter {
+ private Map> completers = new HashMap<>();
+
+ public void addCompleter(String label, Method m, Object obj) {
+ completers.put(label, new AbstractMap.SimpleEntry<>(m, obj));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public List onTabComplete(CommandSender sender, Command command, String label, String[] args) {
+ for(int i = args.length; i >= 0; i--) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(label.toLowerCase());
+
+ for(int x = 0; x < i; x++) {
+ if(!args[x].equals("") && !args[x].equals(" ")) {
+ builder.append(".");
+ builder.append(args[x].toLowerCase());
+ }
+ }
+
+ String cmdLabel = builder.toString();
+
+ if(this.completers.containsKey(cmdLabel)) {
+ Entry entry = this.completers.get(cmdLabel);
+
+ try {
+ return (List) entry.getKey().invoke(entry.getValue(), new CommandData(sender, command, label, args, cmdLabel.split("\\.").length - 1));
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/command/Command.java b/src/main/java/me/hulipvp/hcf/api/command/Command.java
new file mode 100644
index 0000000..d499781
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/command/Command.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.api.command;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Command {
+
+ String label();
+
+ String permission() default "";
+
+ String[] aliases() default {};
+
+ boolean playerOnly() default false;
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/api/command/CommandAPI.java b/src/main/java/me/hulipvp/hcf/api/command/CommandAPI.java
new file mode 100644
index 0000000..b84073e
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/command/CommandAPI.java
@@ -0,0 +1,202 @@
+package me.hulipvp.hcf.api.command;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandMap;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.PluginCommand;
+import org.bukkit.entity.Player;
+import org.bukkit.help.GenericCommandHelpTopic;
+import org.bukkit.help.HelpTopic;
+import org.bukkit.help.HelpTopicComparator;
+import org.bukkit.help.IndexHelpTopic;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.SimplePluginManager;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+public class CommandAPI implements CommandExecutor {
+ private Plugin plugin;
+ private Map> commandMap = new HashMap<>();
+ private CommandMap map;
+ private String root, noPermission, noConsole, unknownCommand;
+
+ public CommandAPI(Plugin plugin, String root, String noPermission, String noConsole, String unknownCommand) {
+ this.plugin = plugin;
+
+ if(plugin.getServer().getPluginManager() instanceof SimplePluginManager) {
+ SimplePluginManager manager = (SimplePluginManager) plugin.getServer().getPluginManager();
+
+ try {
+ Field field = SimplePluginManager.class.getDeclaredField("commandMap");
+ field.setAccessible(true);
+ this.map = (CommandMap) field.get(manager);
+ } catch(IllegalArgumentException | SecurityException | NoSuchFieldException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ }
+
+ this.root = root;
+ this.noPermission = noPermission;
+ this.noConsole = noConsole;
+ this.unknownCommand = unknownCommand;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args) {
+ return handleCommand(sender, cmd, label, args);
+ }
+
+ public boolean handleCommand(CommandSender sender, org.bukkit.command.Command cmd, String label, String[] args) {
+ for(int i = args.length; i >= 0; i--) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(label.toLowerCase());
+
+ for(int x = 0; x < i; x++) {
+ builder.append(".");
+ builder.append(args[x].toLowerCase());
+ }
+
+ String cmdLabel = builder.toString();
+
+ if(this.commandMap.containsKey(cmdLabel)) {
+ Method method = this.commandMap.get(cmdLabel).getKey();
+ Object methodObject = this.commandMap.get(cmdLabel).getValue();
+ Command command = method.getAnnotation(Command.class);
+
+ if(command.permission().length() > 0 && !sender.hasPermission(this.root + "." + command.permission())) {
+ sender.sendMessage(this.noPermission);
+ return true;
+ }
+
+ if(command.playerOnly() && !(sender instanceof Player)) {
+ sender.sendMessage(this.noConsole);
+ return true;
+ }
+
+ try {
+ method.invoke(methodObject, new CommandData(sender, cmd, label, args, cmdLabel.contains("\\.") ? cmdLabel.split("\\.").length - 1 : 0));
+ } catch(IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+ }
+
+ this.defaultCommand(new CommandData(sender, cmd, label, args, 0));
+
+ return true;
+ }
+
+ public void registerCommands(Object obj) {
+ for(Method m : obj.getClass().getMethods()) {
+ if(m.getAnnotation(Command.class) != null) {
+ Command command = m.getAnnotation(Command.class);
+ if(m.getParameterTypes().length > 1 || m.getParameterTypes()[0] != CommandData.class) {
+ System.out.println("Unable to register command " + m.getName() + ". Unexpected method arguments");
+ continue;
+ }
+
+ this.registerCommand(command, command.label(), m, obj);
+ for(String alias : command.aliases())
+ this.registerCommand(command, alias, m, obj);
+ } else if(m.getAnnotation(Completer.class) != null) {
+ Completer comp = m.getAnnotation(Completer.class);
+ if(m.getParameterTypes().length > 1 || m.getParameterTypes().length == 0 || m.getParameterTypes()[0] != CommandData.class) {
+ System.out.println("Unable to register tab completer " + m.getName() + ". Unexpected method arguments");
+ continue;
+ }
+
+ if(m.getReturnType() != List.class) {
+ System.out.println("Unable to register tab completer " + m.getName() + ". Unexpected return type");
+ continue;
+ }
+
+ this.registerCompleter(comp.label(), m, obj);
+ for(String alias : comp.aliases())
+ this.registerCompleter(alias, m, obj);
+ }
+ }
+ }
+
+ public void registerHelp() {
+ Set help = new TreeSet<>(HelpTopicComparator.helpTopicComparatorInstance());
+
+ for(String s : this.commandMap.keySet()) {
+ if(!s.contains(".")) {
+ org.bukkit.command.Command cmd = this.map.getCommand(s);
+ HelpTopic topic = new GenericCommandHelpTopic(cmd);
+ help.add(topic);
+ }
+ }
+
+ IndexHelpTopic topic = new IndexHelpTopic(this.plugin.getName(), "All commands for " + this.plugin.getName(), null, help, "Below is a list of all " + this.plugin.getName() + " commands:");
+ Bukkit.getServer().getHelpMap().addTopic(topic);
+ }
+
+ public void unregisterCommands(Object obj) {
+ for(Method m : obj.getClass().getMethods()) {
+ if(m.getAnnotation(Command.class) != null) {
+ Command command = m.getAnnotation(Command.class);
+ this.commandMap.remove(command.label().toLowerCase());
+ this.commandMap.remove(this.plugin.getName() + ":" + command.label().toLowerCase());
+ this.map.getCommand(command.label().toLowerCase()).unregister(this.map);
+ }
+ }
+ }
+
+ public void registerCommand(Command command, String label, Method m, Object obj) {
+ this.commandMap.put(label.toLowerCase(), new AbstractMap.SimpleEntry<>(m, obj));
+ this.commandMap.put(this.plugin.getName() + ':' + label.toLowerCase(), new AbstractMap.SimpleEntry<>(m, obj));
+ String cmdLabel = label.replace(".", ",").split(",")[0].toLowerCase();
+
+ if(this.map.getCommand(cmdLabel) == null) {
+ org.bukkit.command.Command cmd = new BukkitCommand(cmdLabel, this, this.plugin);
+ this.map.register(this.plugin.getName(), cmd);
+ }
+ }
+
+ public void registerCompleter(String label, Method m, Object obj) {
+ String cmdLabel = label.replace(".", ",").split(",")[0].toLowerCase();
+
+ if(this.map.getCommand(cmdLabel) == null) {
+ org.bukkit.command.Command command = new BukkitCommand(cmdLabel, this, this.plugin);
+ this.map.register(this.plugin.getName(), command);
+ }
+
+ if(this.map.getCommand(cmdLabel) instanceof BukkitCommand) {
+ BukkitCommand command = (BukkitCommand) this.map.getCommand(cmdLabel);
+ if(command.completer == null)
+ command.completer = new BukkitCompleter();
+ command.completer.addCompleter(label, m, obj);
+ } else if(this.map.getCommand(cmdLabel) instanceof PluginCommand) {
+ try {
+ Object command = this.map.getCommand(cmdLabel);
+ Field field = command.getClass().getDeclaredField("completer");
+ field.setAccessible(true);
+
+ if(field.get(command) == null) {
+ BukkitCompleter completer = new BukkitCompleter();
+ completer.addCompleter(label, m, obj);
+ field.set(command, completer);
+ } else if(field.get(command) instanceof BukkitCompleter) {
+ BukkitCompleter completer = (BukkitCompleter) field.get(command);
+ completer.addCompleter(label, m, obj);
+ } else {
+ System.out.println("Unable to register tab completer " + m.getName() + ". A tab completer is already registered for that command!");
+ }
+ } catch(Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ private void defaultCommand(CommandData args) {
+ args.getSender().sendMessage(this.unknownCommand);
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/command/CommandData.java b/src/main/java/me/hulipvp/hcf/api/command/CommandData.java
new file mode 100644
index 0000000..4b3f4cd
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/command/CommandData.java
@@ -0,0 +1,67 @@
+package me.hulipvp.hcf.api.command;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class CommandData {
+ private final CommandSender sender;
+ private final org.bukkit.command.Command command;
+ private final String label;
+ private final String[] args;
+
+ public CommandData(CommandSender sender, org.bukkit.command.Command command, String label, String[] args, int subCommand) {
+ String[] modArgs = new String[args.length - subCommand];
+
+ for(int i = 0; i < args.length - subCommand; i++) {
+ modArgs[i] = args[i + subCommand];
+ }
+
+ StringBuilder builder = new StringBuilder();
+ builder.append(label);
+
+ for(int x = 0; x < subCommand; x++) {
+ builder.append(".");
+ builder.append(args[x]);
+ }
+
+ String cmdLabel = builder.toString();
+
+ this.sender = sender;
+ this.command = command;
+ this.label = cmdLabel;
+ this.args = modArgs;
+ }
+
+ public CommandSender getSender() {
+ return this.sender;
+ }
+
+ public org.bukkit.command.Command getCommand() {
+ return this.command;
+ }
+
+ public String getLabel() {
+ return this.label;
+ }
+
+ public String[] getArgs() {
+ return this.args;
+ }
+
+ public String getArg(int index) {
+ return this.args[index];
+ }
+
+ public int length() {
+ return this.args.length;
+ }
+
+ public Player getPlayer() {
+ if(this.sender instanceof Player) {
+ return (Player) this.sender;
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/command/Completer.java b/src/main/java/me/hulipvp/hcf/api/command/Completer.java
new file mode 100644
index 0000000..379b617
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/command/Completer.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.command;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Completer {
+
+ String label();
+
+ String[] aliases() default {};
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestControlEvent.java b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestControlEvent.java
new file mode 100644
index 0000000..51c0836
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestControlEvent.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.api.events.conquest;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestZone;
+import org.bukkit.entity.Player;
+
+public class ConquestControlEvent extends ConquestEvent {
+
+ @Getter private final ConquestZone zone;
+ @Getter private final Player player;
+
+ public ConquestControlEvent(Conquest conquest, ConquestZone zone, Player player) {
+ super(conquest);
+
+ this.zone = zone;
+ this.player = player;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestEndEvent.java b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestEndEvent.java
new file mode 100644
index 0000000..2996c8e
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestEndEvent.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.events.conquest;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestEndReason;
+
+public class ConquestEndEvent extends ConquestEvent {
+
+ @Getter private final ConquestEndReason reason;
+
+ public ConquestEndEvent(Conquest conquest, ConquestEndReason reason) {
+ super(conquest);
+
+ this.reason = reason;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestEvent.java b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestEvent.java
new file mode 100644
index 0000000..b5d8a4e
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestEvent.java
@@ -0,0 +1,25 @@
+package me.hulipvp.hcf.api.events.conquest;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public abstract class ConquestEvent extends Event {
+
+ private static final HandlerList handlers = new HandlerList();
+
+ @Getter private final Conquest conquest;
+
+ ConquestEvent(Conquest conquest) {
+ this.conquest = conquest;
+ }
+
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestKnockEvent.java b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestKnockEvent.java
new file mode 100644
index 0000000..cb3e0c4
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestKnockEvent.java
@@ -0,0 +1,21 @@
+package me.hulipvp.hcf.api.events.conquest;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestZone;
+import org.bukkit.entity.Player;
+
+public class ConquestKnockEvent extends ConquestEvent {
+
+ @Getter private final ConquestZone zone;
+ @Getter private final int knockTime;
+ @Getter private final Player player;
+
+ public ConquestKnockEvent(Conquest conquest, ConquestZone zone, int knockTime, Player player) {
+ super(conquest);
+
+ this.zone = zone;
+ this.knockTime = knockTime;
+ this.player = player;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestStartEvent.java b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestStartEvent.java
new file mode 100644
index 0000000..f4522f8
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/conquest/ConquestStartEvent.java
@@ -0,0 +1,10 @@
+package me.hulipvp.hcf.api.events.conquest;
+
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+
+public class ConquestStartEvent extends ConquestEvent {
+
+ public ConquestStartEvent(Conquest conquest) {
+ super(conquest);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionClaimEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionClaimEvent.java
new file mode 100644
index 0000000..95e2513
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionClaimEvent.java
@@ -0,0 +1,29 @@
+package me.hulipvp.hcf.api.events.faction.normal;
+
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.game.faction.Claim;
+import me.hulipvp.hcf.game.faction.Faction;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+
+public class FactionClaimEvent extends FactionEvent implements Cancellable {
+
+ @Getter private final Player player;
+
+ @Getter private final Claim claim;
+
+ @Getter @Setter private boolean cancelled;
+
+ public FactionClaimEvent(Faction faction, Player player, Claim claim) {
+ super(faction);
+
+ this.player = player;
+ this.claim = claim;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionCreateEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionCreateEvent.java
new file mode 100644
index 0000000..36be56f
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionCreateEvent.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.events.faction.normal;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.Faction;
+import org.bukkit.entity.Player;
+
+public class FactionCreateEvent extends FactionEvent {
+
+ @Getter private final Player player;
+
+ public FactionCreateEvent(Faction faction, Player player) {
+ super(faction);
+
+ this.player = player;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionDisbandEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionDisbandEvent.java
new file mode 100644
index 0000000..0fa5584
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionDisbandEvent.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.events.faction.normal;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.Faction;
+import org.bukkit.entity.Player;
+
+public class FactionDisbandEvent extends FactionEvent {
+
+ @Getter private final Player player;
+
+ public FactionDisbandEvent(Faction faction, Player player) {
+ super(faction);
+
+ this.player = player;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionEvent.java
new file mode 100644
index 0000000..427d030
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionEvent.java
@@ -0,0 +1,25 @@
+package me.hulipvp.hcf.api.events.faction.normal;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.Faction;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public class FactionEvent extends Event {
+
+ private static final HandlerList handlers = new HandlerList();
+
+ @Getter private final Faction faction;
+
+ FactionEvent(Faction faction) {
+ this.faction = faction;
+ }
+
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionJoinEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionJoinEvent.java
new file mode 100644
index 0000000..594d150
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionJoinEvent.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.events.faction.normal;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.Faction;
+import org.bukkit.entity.Player;
+
+public class FactionJoinEvent extends FactionEvent {
+
+ @Getter private final Player player;
+
+ public FactionJoinEvent(Faction faction, Player player) {
+ super(faction);
+
+ this.player = player;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionLeaveEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionLeaveEvent.java
new file mode 100644
index 0000000..e7b55ee
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/normal/FactionLeaveEvent.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.events.faction.normal;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.Faction;
+import org.bukkit.entity.Player;
+
+public class FactionLeaveEvent extends FactionEvent {
+
+ @Getter private final Player player;
+
+ public FactionLeaveEvent(Faction faction, Player player) {
+ super(faction);
+
+ this.player = player;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionAllyEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionAllyEvent.java
new file mode 100644
index 0000000..ffea04c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionAllyEvent.java
@@ -0,0 +1,15 @@
+package me.hulipvp.hcf.api.events.faction.player;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+
+public class FactionAllyEvent extends PlayerFactionEvent {
+
+ @Getter private final PlayerFaction allied;
+
+ public FactionAllyEvent(PlayerFaction faction, PlayerFaction allied) {
+ super(faction);
+
+ this.allied = allied;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionKickEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionKickEvent.java
new file mode 100644
index 0000000..5a31010
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionKickEvent.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.api.events.faction.player;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import org.bukkit.entity.Player;
+
+public class FactionKickEvent extends PlayerFactionEvent {
+
+ @Getter private final Player player;
+ @Getter private final FactionMember kicked;
+
+ public FactionKickEvent(PlayerFaction faction, Player player, FactionMember kicked) {
+ super(faction);
+
+ this.player = player;
+ this.kicked = kicked;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionPromoteEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionPromoteEvent.java
new file mode 100644
index 0000000..b6f2850
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionPromoteEvent.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.api.events.faction.player;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import org.bukkit.entity.Player;
+
+public class FactionPromoteEvent extends PlayerFactionEvent {
+
+ @Getter private final Player player;
+ @Getter private final FactionMember promoted;
+
+ public FactionPromoteEvent(PlayerFaction faction, Player player, FactionMember promoted) {
+ super(faction);
+
+ this.player = player;
+ this.promoted = promoted;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionUnallyEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionUnallyEvent.java
new file mode 100644
index 0000000..4aff3c5
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/player/FactionUnallyEvent.java
@@ -0,0 +1,15 @@
+package me.hulipvp.hcf.api.events.faction.player;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+
+public class FactionUnallyEvent extends PlayerFactionEvent {
+
+ @Getter private final PlayerFaction allied;
+
+ public FactionUnallyEvent(PlayerFaction faction, PlayerFaction allied) {
+ super(faction);
+
+ this.allied = allied;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/faction/player/PlayerFactionEvent.java b/src/main/java/me/hulipvp/hcf/api/events/faction/player/PlayerFactionEvent.java
new file mode 100644
index 0000000..3ea231c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/faction/player/PlayerFactionEvent.java
@@ -0,0 +1,25 @@
+package me.hulipvp.hcf.api.events.faction.player;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public class PlayerFactionEvent extends Event {
+
+ private static final HandlerList handlers = new HandlerList();
+
+ @Getter private final PlayerFaction faction;
+
+ PlayerFactionEvent(PlayerFaction faction) {
+ this.faction = faction;
+ }
+
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/kit/KitDisableEvent.java b/src/main/java/me/hulipvp/hcf/api/events/kit/KitDisableEvent.java
new file mode 100644
index 0000000..d35bbbc
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/kit/KitDisableEvent.java
@@ -0,0 +1,11 @@
+package me.hulipvp.hcf.api.events.kit;
+
+import me.hulipvp.hcf.game.kits.Kit;
+import org.bukkit.entity.Player;
+
+public class KitDisableEvent extends KitEvent {
+
+ public KitDisableEvent(Player player, Kit kit) {
+ super(player, kit);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/api/events/kit/KitEnableEvent.java b/src/main/java/me/hulipvp/hcf/api/events/kit/KitEnableEvent.java
new file mode 100644
index 0000000..7334e2a
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/kit/KitEnableEvent.java
@@ -0,0 +1,11 @@
+package me.hulipvp.hcf.api.events.kit;
+
+import me.hulipvp.hcf.game.kits.Kit;
+import org.bukkit.entity.Player;
+
+public class KitEnableEvent extends KitEvent {
+
+ public KitEnableEvent(Player player, Kit kit) {
+ super(player, kit);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/kit/KitEvent.java b/src/main/java/me/hulipvp/hcf/api/events/kit/KitEvent.java
new file mode 100644
index 0000000..74d93a9
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/kit/KitEvent.java
@@ -0,0 +1,27 @@
+package me.hulipvp.hcf.api.events.kit;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.kits.Kit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public class KitEvent extends Event {
+ private static final HandlerList handlers = new HandlerList();
+
+ @Getter private final Player player;
+ @Getter private final Kit kit;
+
+ KitEvent(Player player, Kit kit) {
+ this.player = player;
+ this.kit = kit;
+ }
+
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/koth/KothControlEvent.java b/src/main/java/me/hulipvp/hcf/api/events/koth/KothControlEvent.java
new file mode 100644
index 0000000..ccf4059
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/koth/KothControlEvent.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.events.koth;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import org.bukkit.entity.Player;
+
+public class KothControlEvent extends KothEvent {
+
+ @Getter private final Player player;
+
+ public KothControlEvent(Koth koth, Player player) {
+ super(koth);
+
+ this.player = player;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/koth/KothEndEvent.java b/src/main/java/me/hulipvp/hcf/api/events/koth/KothEndEvent.java
new file mode 100644
index 0000000..4d3c132
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/koth/KothEndEvent.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.events.koth;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.event.koth.data.KothEndReason;
+
+public class KothEndEvent extends KothEvent {
+
+ @Getter private final KothEndReason reason;
+
+ public KothEndEvent(Koth koth, KothEndReason reason) {
+ super(koth);
+
+ this.reason = reason;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/koth/KothEvent.java b/src/main/java/me/hulipvp/hcf/api/events/koth/KothEvent.java
new file mode 100644
index 0000000..283fcf0
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/koth/KothEvent.java
@@ -0,0 +1,24 @@
+package me.hulipvp.hcf.api.events.koth;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public abstract class KothEvent extends Event {
+ private static final HandlerList handlers = new HandlerList();
+
+ @Getter private final Koth koth;
+
+ KothEvent(Koth koth) {
+ this.koth = koth;
+ }
+
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/koth/KothKnockEvent.java b/src/main/java/me/hulipvp/hcf/api/events/koth/KothKnockEvent.java
new file mode 100644
index 0000000..bbc058a
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/koth/KothKnockEvent.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.events.koth;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import org.bukkit.entity.Player;
+
+public class KothKnockEvent extends KothEvent {
+
+ @Getter private final Player player;
+
+ public KothKnockEvent(Koth koth, Player player) {
+ super(koth);
+
+ this.player = player;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/koth/KothStartEvent.java b/src/main/java/me/hulipvp/hcf/api/events/koth/KothStartEvent.java
new file mode 100644
index 0000000..492d430
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/koth/KothStartEvent.java
@@ -0,0 +1,10 @@
+package me.hulipvp.hcf.api.events.koth;
+
+import me.hulipvp.hcf.game.event.koth.Koth;
+
+public class KothStartEvent extends KothEvent {
+
+ public KothStartEvent(Koth koth) {
+ super(koth);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/mountain/MountainEvent.java b/src/main/java/me/hulipvp/hcf/api/events/mountain/MountainEvent.java
new file mode 100644
index 0000000..b3bb554
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/mountain/MountainEvent.java
@@ -0,0 +1,25 @@
+package me.hulipvp.hcf.api.events.mountain;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public class MountainEvent extends Event {
+
+ private static final HandlerList handlers = new HandlerList();
+
+ @Getter private final Mountain mountain;
+
+ MountainEvent(Mountain mountain) {
+ this.mountain = mountain;
+ }
+
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/mountain/MountainResetEvent.java b/src/main/java/me/hulipvp/hcf/api/events/mountain/MountainResetEvent.java
new file mode 100644
index 0000000..b112bbe
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/mountain/MountainResetEvent.java
@@ -0,0 +1,15 @@
+package me.hulipvp.hcf.api.events.mountain;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+
+public class MountainResetEvent extends MountainEvent {
+
+ @Getter private final Long resetTime;
+
+ public MountainResetEvent(Mountain mountain, Long resetTime) {
+ super(mountain);
+
+ this.resetTime = resetTime;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/timer/TimerEvent.java b/src/main/java/me/hulipvp/hcf/api/events/timer/TimerEvent.java
new file mode 100644
index 0000000..d571bd8
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/timer/TimerEvent.java
@@ -0,0 +1,25 @@
+package me.hulipvp.hcf.api.events.timer;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.timer.Timer;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+
+public abstract class TimerEvent extends Event {
+
+ private static final HandlerList handlers = new HandlerList();
+
+ @Getter private Timer timer;
+
+ TimerEvent(Timer timer) {
+ this.timer = timer;
+ }
+
+ public HandlerList getHandlers() {
+ return handlers;
+ }
+
+ public static HandlerList getHandlerList() {
+ return handlers;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/timer/TimerExpireEvent.java b/src/main/java/me/hulipvp/hcf/api/events/timer/TimerExpireEvent.java
new file mode 100644
index 0000000..ecf99c0
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/timer/TimerExpireEvent.java
@@ -0,0 +1,10 @@
+package me.hulipvp.hcf.api.events.timer;
+
+import me.hulipvp.hcf.game.timer.Timer;
+
+public class TimerExpireEvent extends TimerEvent {
+
+ public TimerExpireEvent(Timer timer) {
+ super(timer);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/timer/TimerPauseEvent.java b/src/main/java/me/hulipvp/hcf/api/events/timer/TimerPauseEvent.java
new file mode 100644
index 0000000..86b1e72
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/timer/TimerPauseEvent.java
@@ -0,0 +1,10 @@
+package me.hulipvp.hcf.api.events.timer;
+
+import me.hulipvp.hcf.game.timer.Timer;
+
+public class TimerPauseEvent extends TimerEvent {
+
+ public TimerPauseEvent(Timer timer) {
+ super(timer);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/events/timer/TimerUnpauseEvent.java b/src/main/java/me/hulipvp/hcf/api/events/timer/TimerUnpauseEvent.java
new file mode 100644
index 0000000..f9ab44c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/events/timer/TimerUnpauseEvent.java
@@ -0,0 +1,10 @@
+package me.hulipvp.hcf.api.events.timer;
+
+import me.hulipvp.hcf.game.timer.Timer;
+
+public class TimerUnpauseEvent extends TimerEvent {
+
+ public TimerUnpauseEvent(Timer timer) {
+ super(timer);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/hooks/plugins/PlayerHook.java b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/PlayerHook.java
new file mode 100644
index 0000000..81db9c7
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/PlayerHook.java
@@ -0,0 +1,14 @@
+package me.hulipvp.hcf.api.hooks.plugins;
+
+import org.bukkit.entity.Player;
+
+public interface PlayerHook {
+
+ boolean canChat(Player player);
+
+ String getRankName(Player player);
+
+ String getRankPrefix(Player player);
+
+ String getRankSuffix(Player player);
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/hooks/plugins/core/CoreHook.java b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/core/CoreHook.java
new file mode 100644
index 0000000..c154b60
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/core/CoreHook.java
@@ -0,0 +1,73 @@
+package me.hulipvp.hcf.api.hooks.plugins.core;
+
+import com.verispvp.core.api.CoreAPI;
+import com.verispvp.core.api.minecrafter.Minecrafter;
+import com.verispvp.core.api.rank.Rank;
+import lombok.Getter;
+import me.hulipvp.hcf.api.hooks.plugins.PlayerHook;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class CoreHook implements PlayerHook {
+
+ @Getter private boolean hooked;
+
+ public CoreHook() {
+ this.hooked = true;
+ Bukkit.getLogger().info("Successfully hooked into Core.");
+ }
+
+ public static boolean canHook() {
+ if(Bukkit.getServer().getPluginManager().getPlugin("Core") == null)
+ return false;
+
+ try {
+ Class.forName("com.verispvp.core.api.CoreAPI");
+ return true;
+ } catch(ClassNotFoundException ex) {
+ return false;
+ }
+ }
+
+ public Minecrafter getMinecrafter(Player player) {
+ return CoreAPI.INSTANCE.getMinecrafter(player);
+ }
+
+ public boolean isMuted(Player player) {
+ return getMinecrafter(player).getMute() != null;
+ }
+
+ @Override
+ public boolean canChat(Player player) {
+ Minecrafter minecrafter = getMinecrafter(player);
+
+ return !minecrafter.isAdminChat() && !minecrafter.isStaffChat() && !isMuted(player);
+ }
+
+ public Rank getRank(Player player) {
+ return CoreAPI.INSTANCE.getRank(player);
+ }
+
+ @Override
+ public String getRankName(Player player) {
+ Rank rank = getRank(player);
+ if(rank == null)
+ return "";
+
+ return rank.getName();
+ }
+
+ @Override
+ public String getRankPrefix(Player player) {
+ Rank rank = getRank(player);
+ if(rank == null)
+ return "";
+
+ return rank.getPrefix() + " " + rank.getColor();
+ }
+
+ @Override
+ public String getRankSuffix(Player player) {
+ return "";
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/DataImpl.java b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/DataImpl.java
new file mode 100644
index 0000000..cc511b1
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/DataImpl.java
@@ -0,0 +1,12 @@
+package me.hulipvp.hcf.api.hooks.plugins.nucleus;
+
+import org.bukkit.entity.Player;
+
+public interface DataImpl {
+
+ boolean canChat(Player player);
+
+ String getRankName(Player player);
+
+ String getRankPrefix(Player player);
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/NucleusHook.java b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/NucleusHook.java
new file mode 100644
index 0000000..eb64911
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/NucleusHook.java
@@ -0,0 +1,50 @@
+package me.hulipvp.hcf.api.hooks.plugins.nucleus;
+
+import lombok.Getter;
+import me.hulipvp.hcf.api.hooks.plugins.PlayerHook;
+import me.hulipvp.hcf.api.hooks.plugins.nucleus.impl.NucleusPlayerImpl;
+import me.hulipvp.hcf.api.hooks.plugins.nucleus.impl.PlayerDataImpl;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class NucleusHook implements PlayerHook {
+
+ @Getter private boolean hooked;
+ @Getter private DataImpl dataImpl;
+
+ public NucleusHook() {
+ try {
+ Class.forName("me.joeleoli.nucleus.player.PlayerData");
+ dataImpl = new PlayerDataImpl();
+ } catch(ClassNotFoundException ex) {
+ dataImpl = new NucleusPlayerImpl();
+ } // We do this cuz this fool joeleoli keeps fricken changing his fricken API for Nucleus
+
+ this.hooked = true;
+ Bukkit.getLogger().info("Successfully hooked into Nucleus.");
+ }
+
+ public static boolean canHook() {
+ return Bukkit.getServer().getPluginManager().getPlugin("Nucleus") != null;
+ }
+
+ @Override
+ public boolean canChat(Player player) {
+ return dataImpl.canChat(player);
+ }
+
+ @Override
+ public String getRankName(Player player) {
+ return dataImpl.getRankName(player);
+ }
+
+ @Override
+ public String getRankPrefix(Player player) {
+ return dataImpl.getRankPrefix(player);
+ }
+
+ @Override
+ public String getRankSuffix(Player player) {
+ return "";
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/impl/NucleusPlayerImpl.java b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/impl/NucleusPlayerImpl.java
new file mode 100644
index 0000000..be947df
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/impl/NucleusPlayerImpl.java
@@ -0,0 +1,51 @@
+package me.hulipvp.hcf.api.hooks.plugins.nucleus.impl;
+
+import me.hulipvp.hcf.api.hooks.plugins.nucleus.DataImpl;
+import me.joeleoli.nucleus.Nucleus;
+import me.joeleoli.nucleus.chat.ChatManager;
+import me.joeleoli.nucleus.player.NucleusPlayer;
+import me.joeleoli.nucleus.rank.Rank;
+import org.bukkit.entity.Player;
+
+public class NucleusPlayerImpl implements DataImpl {
+
+ private NucleusPlayer getData(Player player) {
+ NucleusPlayer nucleusPlayer = NucleusPlayer.getByUuid(player.getUniqueId());
+ if(!nucleusPlayer.isLoaded())
+ nucleusPlayer.load();
+
+ return nucleusPlayer;
+ }
+
+ @Override
+ public boolean canChat(Player player) {
+ ChatManager chatManager = Nucleus.getInstance().getChatManager();
+ NucleusPlayer nucleusPlayer = NucleusPlayer.getByUuid(player.getUniqueId());
+
+ return !chatManager.isChatMuted() && chatManager.getDelayTime() <= 0 && nucleusPlayer.getActiveMute() == null;
+ }
+
+ public Rank getRank(Player player) {
+ NucleusPlayer nucleusPlayer = getData(player);
+
+ return nucleusPlayer.getGlobalRank() != null ? nucleusPlayer.getGlobalRank() : nucleusPlayer.getActiveRank();
+ }
+
+ @Override
+ public String getRankName(Player player) {
+ Rank rank = getRank(player);
+ if(rank == null)
+ return "";
+
+ return rank.getName();
+ }
+
+ @Override
+ public String getRankPrefix(Player player) {
+ Rank rank = getRank(player);
+ if(rank == null)
+ return "";
+
+ return rank.getPrefix();
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/impl/PlayerDataImpl.java b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/impl/PlayerDataImpl.java
new file mode 100644
index 0000000..26aeff2
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/nucleus/impl/PlayerDataImpl.java
@@ -0,0 +1,73 @@
+package me.hulipvp.hcf.api.hooks.plugins.nucleus.impl;
+
+import me.hulipvp.hcf.api.hooks.plugins.nucleus.DataImpl;
+import me.joeleoli.nucleus.chat.ChatManager;
+import me.joeleoli.nucleus.player.NucleusPlayer;
+import me.joeleoli.nucleus.rank.Rank;
+import org.bukkit.entity.Player;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+public class PlayerDataImpl implements DataImpl {
+
+ private static Field chatMuted, chatDelay;
+
+ private NucleusPlayer getData(Player player) {
+ NucleusPlayer playerData = NucleusPlayer.getByUuid(player.getUniqueId());
+ if(!playerData.isLoaded())
+ playerData.load();
+
+ return playerData;
+ }
+
+ @Override
+ public boolean canChat(Player player) {
+ if(chatMuted == null || chatDelay == null)
+ return true;
+
+ NucleusPlayer playerData = getData(player);
+
+ try {
+ return !chatMuted.getBoolean(null) && chatDelay.getInt(null) <= 0 && playerData.getActiveMute() == null;
+ } catch(IllegalArgumentException | IllegalAccessException ex) {
+ return true;
+ }
+ }
+
+ public Rank getRank(Player player) {
+ NucleusPlayer playerData = getData(player);
+
+ return playerData.getGlobalRank() != null ? playerData.getGlobalRank() : playerData.getActiveRank();
+ }
+
+ @Override
+ public String getRankName(Player player) {
+ Rank rank = getRank(player);
+ if(rank == null)
+ return "";
+
+ return rank.getName();
+ }
+
+ @Override
+ public String getRankPrefix(Player player) {
+ Rank rank = getRank(player);
+ if(rank == null)
+ return "";
+
+ return rank.getPrefix();
+ }
+
+ static {
+ for(Field field : ChatManager.class.getDeclaredFields()) {
+ if(!Modifier.isStatic(field.getModifiers()))
+ continue;
+
+ if(field.getName().equals("publicChatMuted"))
+ chatMuted = field;
+ else if(field.getName().equals("chatDelay"))
+ chatDelay = field;
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/hooks/plugins/vault/VaultHook.java b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/vault/VaultHook.java
new file mode 100644
index 0000000..1660718
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/hooks/plugins/vault/VaultHook.java
@@ -0,0 +1,63 @@
+package me.hulipvp.hcf.api.hooks.plugins.vault;
+
+import lombok.Getter;
+import me.hulipvp.hcf.api.hooks.plugins.PlayerHook;
+import net.milkbowl.vault.chat.Chat;
+import net.milkbowl.vault.permission.Permission;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.RegisteredServiceProvider;
+
+public class VaultHook implements PlayerHook {
+
+ @Getter private Permission perms;
+ @Getter private Chat chat;
+
+ @Getter private boolean hooked;
+
+ public VaultHook() {
+ RegisteredServiceProvider permsRsp = Bukkit.getServer().getServicesManager().getRegistration(Permission.class);
+ if(permsRsp != null && permsRsp.getProvider() != null)
+ this.perms = permsRsp.getProvider();
+
+ RegisteredServiceProvider chatRsp = Bukkit.getServer().getServicesManager().getRegistration(Chat.class);
+ if(chatRsp != null && chatRsp.getProvider() != null)
+ this.chat = chatRsp.getProvider();
+
+ this.hooked = true;
+ Bukkit.getLogger().info("Successfully hooked into Vault.");
+ }
+
+ public static boolean canHook() {
+ return Bukkit.getServer().getPluginManager().getPlugin("Vault") != null;
+ }
+
+ @Override
+ public boolean canChat(Player player) {
+ return true;
+ }
+
+ @Override
+ public String getRankName(Player player) {
+ if(chat == null)
+ return "";
+
+ return chat.getPrimaryGroup(player);
+ }
+
+ @Override
+ public String getRankPrefix(Player player) {
+ if(chat == null)
+ return "";
+
+ return chat.getPlayerPrefix(player);
+ }
+
+ @Override
+ public String getRankSuffix(Player player) {
+ if(chat == null)
+ return "";
+
+ return chat.getPlayerSuffix(player);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/hooks/server/ProtocolHook.java b/src/main/java/me/hulipvp/hcf/api/hooks/server/ProtocolHook.java
new file mode 100644
index 0000000..50757e4
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/hooks/server/ProtocolHook.java
@@ -0,0 +1,105 @@
+package me.hulipvp.hcf.api.hooks.server;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.ProtocolLibrary;
+import com.comphenix.protocol.ProtocolManager;
+import com.comphenix.protocol.events.ListenerPriority;
+import com.comphenix.protocol.events.PacketAdapter;
+import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.reflect.FieldAccessException;
+import com.comphenix.protocol.reflect.StructureModifier;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.listeners.GlassListener;
+import net.minecraft.server.v1_7_R4.EntityPlayer;
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.v1_7_R4.entity.CraftPlayer;
+import org.bukkit.entity.Player;
+
+public class ProtocolHook {
+
+ public ProtocolHook() { // Thank you iHCF
+ try {
+ ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
+ protocolManager.addPacketListener(new PacketAdapter(HCF.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Client.BLOCK_PLACE) {
+ @Override
+ public void onPacketReceiving(PacketEvent event) {
+ StructureModifier modifier = event.getPacket().getIntegers();
+ Player player = event.getPlayer();
+
+ try {
+ int face = modifier.read(3);
+ if(face == 255)
+ return;
+
+ Location clickedBlock = new Location(player.getWorld(), modifier.read(0), modifier.read(1), modifier.read(2));
+ if(GlassListener.hasGlass(player, clickedBlock)) {
+ Location placedLocation = clickedBlock.clone();
+ switch(face) {
+ case 2:
+ placedLocation.add(0, 0, -1);
+ break;
+ case 3:
+ placedLocation.add(0, 0, 1);
+ break;
+ case 4:
+ placedLocation.add(-1, 0, 0);
+ break;
+ case 5:
+ placedLocation.add(1, 0, 0);
+ break;
+ default:
+ return;
+ }
+
+ event.setCancelled(true);
+
+ if(!GlassListener.hasGlass(player, clickedBlock)) {
+ event.setCancelled(true);
+ player.sendBlockChange(placedLocation, Material.AIR, (byte) 0);
+ }
+ }
+ } catch(FieldAccessException ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+
+ protocolManager.addPacketListener(new PacketAdapter(HCF.getInstance(), ListenerPriority.NORMAL, PacketType.Play.Client.BLOCK_DIG) {
+ @Override
+ public void onPacketReceiving(PacketEvent event) {
+ StructureModifier modifier = event.getPacket().getIntegers();
+
+ try {
+ int status = modifier.read(4);
+ if(status == 0 || status == 2) {
+ Player player = event.getPlayer();
+ int x = modifier.read(0), y = modifier.read(1), z = modifier.read(2);
+ Location location = new Location(player.getWorld(), x, y, z);
+ if(GlassListener.hasGlass(player, location)) {
+ event.setCancelled(true);
+ if(status == 2) {
+ player.sendBlockChange(location, 95, (byte) 14);
+ } else if(status == 0) { // we check this because Blocks that broke pretty much straight away do not send a FINISHED for some weird reason.
+ EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
+ if(player.getGameMode() == GameMode.CREATIVE || entityPlayer.world.getType(x, y, z).getDamage(entityPlayer, entityPlayer.world, x, y, z) >= 1.0F)
+ player.sendBlockChange(location, 95, (byte) 14);
+ }
+ }
+ }
+ } catch(FieldAccessException ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+ } catch(Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ public static boolean canHook() {
+ return Bukkit.getServer().getPluginManager().getPlugin("ProtocolLib") != null;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/IModule.java b/src/main/java/me/hulipvp/hcf/api/modules/IModule.java
new file mode 100644
index 0000000..90a3b3f
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/IModule.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.api.modules;
+
+public interface IModule {
+
+ /**
+ * Called when the module has started loading
+ */
+ void onLoad();
+
+ /**
+ * Called when the module is done loading
+ */
+ void onEnable();
+
+ /**
+ * Called when the module gets disabled... duh
+ */
+ void onDisable();
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/JavaModuleLoader.java b/src/main/java/me/hulipvp/hcf/api/modules/JavaModuleLoader.java
new file mode 100644
index 0000000..f40b3d4
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/JavaModuleLoader.java
@@ -0,0 +1,146 @@
+package me.hulipvp.hcf.api.modules;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.modules.ex.InvalidModuleException;
+import me.hulipvp.hcf.api.modules.ex.InvalidModuleInfoException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.logging.Level;
+
+public class JavaModuleLoader {
+
+ private final Map> classes = new ConcurrentHashMap<>();
+ private final Map loaders = new LinkedHashMap<>();
+
+ public Module loadModule(File file)
+ throws InvalidModuleException {
+ if(!file.exists())
+ throw new InvalidModuleException(new FileNotFoundException(file.getPath() + " does not exist"));
+
+ ModuleInfoFile information;
+
+ try {
+ information = this.getModuleInfoFile(file);
+ } catch(InvalidModuleInfoException ex) {
+ throw new InvalidModuleException(ex);
+ }
+
+ ModuleClassLoader loader;
+
+ try {
+ loader = new ModuleClassLoader(this.getClass().getClassLoader(), this, information, file);
+ } catch(InvalidModuleException ex) {
+ throw ex;
+ } catch(Throwable ex) {
+ throw new InvalidModuleException(ex);
+ }
+
+ this.loaders.put(information.getName(), loader);
+
+ return loader.getModule();
+ }
+
+
+ public void enableModule(Module module) {
+ if(!module.isEnabled()) {
+ if(!this.loaders.containsKey(module.getInfo().getName()))
+ this.loaders.put(module.getInfo().getName(), (ModuleClassLoader) module.getClassLoader());
+
+ try {
+ module.setEnabled(true);
+ } catch(Throwable e) {
+ HCF.getInstance().getLogger().log(Level.SEVERE, "Error occurred while enabling " + module.getInfo().getName(), e);
+ }
+ }
+ }
+
+
+ public void disableModule(Module module) {
+ if(module.isEnabled()) {
+ ClassLoader classLoader = module.getClassLoader();
+ try {
+ module.setEnabled(false);
+ module.kill();
+ } catch(Throwable e) {
+ HCF.getInstance().getLogger().log(Level.SEVERE, "Error occurred while disabling " + module.getInfo().getName(), e);
+ }
+
+ this.loaders.remove(module.getInfo().getName());
+ if(!(classLoader instanceof ModuleClassLoader))
+ return;
+
+ ModuleClassLoader loader = (ModuleClassLoader) classLoader;
+ Set names = loader.getClasses().keySet();
+
+ names.forEach(this::removeClass);
+ }
+ }
+
+ public ModuleInfoFile getModuleInfoFile(File file)
+ throws InvalidModuleInfoException {
+ JarFile jar = null;
+ InputStream stream = null;
+
+ try {
+ jar = new JarFile(file);
+ JarEntry entry = jar.getJarEntry("info.yml");
+ if(entry == null)
+ throw new InvalidModuleInfoException(new FileNotFoundException("Module file does not contain info.yml"));
+
+ stream = jar.getInputStream(entry);
+
+ return new ModuleInfoFile(stream);
+ } catch(IOException e) {
+ throw new InvalidModuleInfoException(e);
+ } finally {
+ if(jar != null) {
+ try {
+ jar.close();
+ } catch(IOException ignored) { }
+ }
+
+ if(stream != null) {
+ try {
+ stream.close();
+ } catch(IOException ignored) { }
+ }
+ }
+ }
+
+ public Class> getClassByName(String name) {
+ Class> cachedClass = this.classes.get(name);
+ if(cachedClass != null)
+ return cachedClass;
+
+ for(String current : this.loaders.keySet()) {
+ ModuleClassLoader loader = this.loaders.get(current);
+
+ try {
+ cachedClass = loader.findClass(name, false);
+ } catch(ClassNotFoundException ignored) { }
+
+ if(cachedClass != null)
+ return cachedClass;
+ }
+
+ return null;
+ }
+
+ public void setClass(String name, Class> clazz) {
+ if(!this.classes.containsKey(name))
+ this.classes.put(name, clazz);
+ }
+
+ private void removeClass(String name) {
+ this.classes.remove(name);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/Module.java b/src/main/java/me/hulipvp/hcf/api/modules/Module.java
new file mode 100644
index 0000000..977ba51
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/Module.java
@@ -0,0 +1,128 @@
+package me.hulipvp.hcf.api.modules;
+
+import lombok.Getter;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.modules.ex.InvalidModuleLoaderException;
+import me.hulipvp.hcf.api.modules.ex.ModuleLoadException;
+import org.bukkit.Bukkit;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.scheduler.BukkitTask;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public abstract class Module implements IModule {
+
+ @Getter private static HCF plugin = HCF.getInstance();
+
+ @Getter private JavaModuleLoader loader;
+
+ @Getter private boolean loaded, enabled;
+
+ @Getter private ClassLoader classLoader;
+ @Getter private ModuleInfoFile info;
+
+ private Set commands;
+ private Set listeners;
+ private Set tasks;
+
+ public Module() {
+ ClassLoader loader = this.getClass().getClassLoader();
+ if(!(loader instanceof ModuleClassLoader))
+ throw new InvalidModuleLoaderException(this.getClass().getName());
+
+ ((ModuleClassLoader) loader).instate(this);
+
+ commands = new HashSet<>();
+ listeners = new HashSet<>();
+ tasks = new HashSet<>();
+ }
+
+ public void onLoad() { }
+
+ public void onEnable() { }
+
+ public void onDisable() { }
+
+ public void kill() {
+ unregisterCommands();
+ unregisterListeners();
+ unregisterTasks();
+ }
+
+ public void setEnabled(boolean enabled)
+ throws ModuleLoadException {
+ if(this.enabled == enabled)
+ throw new ModuleLoadException(getInfo().getName(), "Attempted to enable when initialized.");
+
+ this.enabled = enabled;
+
+ if(enabled)
+ this.onEnable();
+ else
+ this.onDisable();
+ }
+
+ public void setLoaded(boolean loaded) {
+ this.loaded = loaded;
+ }
+
+ public void registerCommand(Object object) {
+ if(commands.add(object))
+ HCF.getInstance().getCommandManager().registerCommands(object);
+ }
+
+ public void unregisterCommand(Object object) {
+ if(commands.remove(object))
+ HCF.getInstance().getCommandManager().unregisterCommands(object);
+ }
+
+ public void unregisterCommands() {
+ commands.forEach(this::unregisterCommand);
+ commands.clear();
+ }
+
+ public void registerListener(T t) {
+ if(listeners.add(t))
+ HCF.getInstance().getListenerManager().registerListener(t);
+ }
+
+ public void unregisterListener(T t) {
+ if(listeners.remove(t))
+ HandlerList.unregisterAll(t);
+ }
+
+ public void unregisterListeners() {
+ listeners.forEach(this::unregisterListener);
+ listeners.clear();
+ }
+
+ public void registerSyncRepeatingTask(Runnable runnable, long delay, long period) {
+ registerTask(Bukkit.getScheduler().runTaskTimer(getPlugin(), runnable, delay, period));
+ }
+
+ public void registerAsyncRepeatingTask(Runnable runnable, long delay, long period) {
+ registerTask(Bukkit.getScheduler().runTaskTimerAsynchronously(getPlugin(), runnable, delay, period));
+ }
+
+ public void registerTask(BukkitTask task) {
+ tasks.add(task.getTaskId());
+ }
+
+ public void unregisterTask(BukkitTask task) {
+ if(tasks.remove(task.getTaskId()))
+ Bukkit.getScheduler().cancelTask(task.getTaskId());
+ }
+
+ public void unregisterTasks() {
+ tasks.forEach(Bukkit.getScheduler()::cancelTask);
+ tasks.clear();
+ }
+
+ protected void instate(JavaModuleLoader loader, ModuleInfoFile info, ClassLoader classLoader) {
+ this.loader = loader;
+ this.info = info;
+ this.classLoader = classLoader;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/ModuleClassLoader.java b/src/main/java/me/hulipvp/hcf/api/modules/ModuleClassLoader.java
new file mode 100644
index 0000000..75fc86a
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/ModuleClassLoader.java
@@ -0,0 +1,108 @@
+package me.hulipvp.hcf.api.modules;
+
+import lombok.Getter;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.modules.ex.InvalidModuleException;
+import me.hulipvp.hcf.api.modules.ex.ModuleLoadException;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+
+public class ModuleClassLoader extends URLClassLoader {
+
+ @Getter private JavaModuleLoader loader;
+
+ @Getter private final Map> classes = new ConcurrentHashMap<>();
+ @Getter private final Module module;
+ @Getter private final ModuleInfoFile info;
+
+ private Module moduleInit;
+ private IllegalStateException state;
+
+ static {
+ try {
+ Method method = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable");
+ if(method != null) {
+ boolean oldAccessible = method.isAccessible();
+
+ method.setAccessible(true);
+ method.invoke(null);
+ method.setAccessible(oldAccessible);
+ HCF.getInstance().getLogger().info("Successfully set ModuleClassLoader as parallel capable");
+ }
+ } catch(Exception e) {
+ HCF.getInstance().getLogger().log(Level.WARNING, "Error setting ModuleClassLoader as parallel capable", e);
+ }
+ }
+
+ public ModuleClassLoader(ClassLoader parent, JavaModuleLoader loader, ModuleInfoFile info, File file) throws InvalidModuleException, MalformedURLException {
+ super(new URL[]{file.toURI().toURL()}, parent);
+
+ this.loader = loader;
+ this.info = info;
+
+ try {
+ Class> jarClass;
+ try {
+ jarClass = Class.forName(info.getMain(), true, this);
+ } catch(ClassNotFoundException e) {
+ throw new InvalidModuleException("Module " + info.getName() + "'s main class does not exist. (" + info.getMain() + ")", e);
+ }
+
+ Class extends Module> mainClass;
+ try {
+ mainClass = jarClass.asSubclass(Module.class);
+ } catch(ClassCastException e) {
+ throw new InvalidModuleException("Module " + info.getName() + "'s main class does not extend Module. (" + info.getMain() + ")", e);
+ }
+
+ this.module = mainClass.newInstance();
+ } catch(IllegalAccessException e) {
+ throw new InvalidModuleException("Module " + info.getName() + " doesn't have a public constructor", e);
+ } catch(InstantiationException e) {
+ throw new InvalidModuleException("Module " + info.getName() + " is not a proper type.", e);
+ }
+ }
+
+ @Override
+ public Class> findClass(String name) throws ClassNotFoundException {
+ return this.findClass(name, true);
+ }
+
+ public Class> findClass(String name, boolean global) throws ClassNotFoundException {
+ Class> result = this.classes.get(name);
+ if(result == null) {
+ if(global)
+ result = this.loader.getClassByName(name);
+
+ if(result == null) {
+ result = super.findClass(name);
+ if(result != null)
+ this.loader.setClass(name, result);
+ }
+
+ this.classes.put(name, result);
+ }
+
+ return result;
+ }
+
+ public void instate(Module module) {
+ if(module.getClass().getClassLoader() != this)
+ throw new ModuleLoadException(module.getInfo().getName(), "Cannot initialize module outside of ModuleClassLoader.");
+
+ if(this.module != null || this.moduleInit != null)
+ throw new IllegalArgumentException("Module already instated.", this.state);
+
+ this.state = new IllegalStateException("Already instated");
+ this.moduleInit = module;
+
+ module.instate(this.loader, this.info, this);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/ModuleInfoFile.java b/src/main/java/me/hulipvp/hcf/api/modules/ModuleInfoFile.java
new file mode 100644
index 0000000..4e11b0f
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/ModuleInfoFile.java
@@ -0,0 +1,67 @@
+package me.hulipvp.hcf.api.modules;
+
+import lombok.Getter;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.modules.ex.InvalidModuleInfoException;
+import org.yaml.snakeyaml.Yaml;
+
+import java.io.InputStream;
+import java.util.Map;
+
+public class ModuleInfoFile {
+
+ private static final Yaml YAML = new Yaml();
+
+ @Getter private String name;
+ @Getter private String rawName;
+ @Getter private String version;
+ @Getter private String main;
+
+ public ModuleInfoFile(InputStream stream)
+ throws InvalidModuleInfoException {
+ this.loadMap(this.asMap(YAML.load(stream)));
+ }
+
+ private void loadMap(Map, ?> map)
+ throws InvalidModuleInfoException {
+ try {
+ this.name = this.rawName = map.get("name").toString();
+
+ if(!this.name.matches("^[A-Za-z0-9 _.-]+$"))
+ throw new InvalidModuleInfoException("Module Name '" + this.name + "' contains invalid characters.");
+
+ this.name = this.name.replace(' ', '_');
+ } catch(NullPointerException e) {
+ throw new InvalidModuleInfoException("Module name is null", e);
+ } catch(ClassCastException e) {
+ throw new InvalidModuleInfoException("Module name is not a string", e);
+ }
+
+ try {
+ this.version = map.get("version").toString();
+ } catch(NullPointerException e) {
+ throw new InvalidModuleInfoException("Module version is null", e);
+ } catch(ClassCastException e) {
+ throw new InvalidModuleInfoException("Module version is not a string", e);
+ }
+
+ try {
+ this.main = map.get("main").toString();
+
+ if(this.main.startsWith(HCF.class.getPackage().getName()))
+ throw new InvalidModuleInfoException("A module cannot be within the namespace of " + HCF.class.getPackage().getName());
+ } catch(NullPointerException e) {
+ throw new InvalidModuleInfoException("Main Class is null", e);
+ } catch(ClassCastException e) {
+ throw new InvalidModuleInfoException("Main Class is not a string", e);
+ }
+ }
+
+ private Map, ?> asMap(Object object)
+ throws InvalidModuleInfoException {
+ if(object instanceof Map)
+ return (Map, ?>) object;
+
+ throw new InvalidModuleInfoException(object + " is not properly structured.");
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/ModuleManager.java b/src/main/java/me/hulipvp/hcf/api/modules/ModuleManager.java
new file mode 100644
index 0000000..89df7fb
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/ModuleManager.java
@@ -0,0 +1,133 @@
+package me.hulipvp.hcf.api.modules;
+
+import lombok.Getter;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.modules.ex.InvalidModuleException;
+import me.hulipvp.hcf.api.modules.ex.InvalidModuleInfoException;
+import org.bukkit.Bukkit;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class ModuleManager {
+
+ @Getter private final Map modules = new HashMap<>();
+ @Getter private final Pattern pattern = Pattern.compile("\\.jar$");
+ @Getter private final JavaModuleLoader loader;
+
+ public ModuleManager() {
+ this.loader = new JavaModuleLoader();
+ }
+
+ public Module loadModule(File file)
+ throws InvalidModuleException {
+ Module result = null;
+
+ String name = file.getName();
+ Matcher matcher = this.pattern.matcher(name);
+ if(matcher.find())
+ result = this.loader.loadModule(file);
+
+ if(result != null) {
+ this.modules.put(result.getInfo().getName(), result);
+
+ result.onLoad();
+ result.setLoaded(true);
+
+ return result;
+ }
+
+ return null;
+ }
+
+ public boolean enableModule(Module module) {
+ if(!module.isEnabled()) {
+ try {
+ module.getLoader().enableModule(module);
+
+ return true;
+ } catch(Throwable e) {
+ HCF.getInstance().getLogger().log(Level.SEVERE, "Error occurred (in the module loader) while enabling " + module.getInfo().getName(), e);
+ }
+ }
+
+ return false;
+ }
+
+ public void disableModule(Module module) {
+ if(module.isEnabled()) {
+ try {
+ module.getLoader().disableModule(module);
+ } catch(Throwable e) {
+ HCF.getInstance().getLogger().log(Level.SEVERE, "Error occurred (in the module loader) while disabling " + module.getInfo().getName(), e);
+ }
+ }
+
+ modules.remove(module.getInfo().getName());
+ }
+
+ public void loadModules() {
+ File directory = new File(HCF.getInstance().getDataFolder() + File.separator + "modules");
+ if(!directory.exists()) {
+ if(directory.mkdir())
+ Bukkit.getLogger().info("Created modules directory.");
+ else
+ Bukkit.getLogger().info("Failed to create modules directory.");
+ }
+
+ if(!directory.isDirectory())
+ throw new IllegalStateException("Invalid directory.");
+
+ Map tempModules = new HashMap<>();
+ for(File file : Objects.requireNonNull(directory.listFiles())) {
+ ModuleInfoFile info;
+
+ try {
+ info = this.loader.getModuleInfoFile(file);
+ String name = info.getName();
+
+ if(name.equalsIgnoreCase("HCF")) {
+ HCF.getInstance().getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + ", Restricted Name.");
+ continue;
+ }
+ } catch(InvalidModuleInfoException e) {
+ HCF.getInstance().getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "'", e);
+ continue;
+ }
+
+ tempModules.put(info.getName(), file);
+ }
+
+ while(!tempModules.isEmpty()) {
+ Iterator ite = tempModules.keySet().iterator();
+
+ while(ite.hasNext()) {
+ String plugin = ite.next();
+ File file = tempModules.get(plugin);
+ ite.remove();
+
+ try {
+ this.loadModule(file);
+ } catch(InvalidModuleException e) {
+ HCF.getInstance().getLogger().log(Level.SEVERE, "Could not load '" + file.getPath() + "'", e);
+ }
+ }
+ }
+
+ modules.values().forEach(this::enableModule);
+ }
+
+ public void disableModules() {
+ modules.values().forEach(this::disableModule);
+ }
+
+ public Module getModule(String name) {
+ return getModules().get(name);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/ex/InvalidModuleException.java b/src/main/java/me/hulipvp/hcf/api/modules/ex/InvalidModuleException.java
new file mode 100644
index 0000000..7771575
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/ex/InvalidModuleException.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.modules.ex;
+
+public class InvalidModuleException extends Exception {
+
+ public InvalidModuleException(String message) {
+ super("[Module] " + message);
+ }
+
+ public InvalidModuleException(Throwable throwable) {
+ super(throwable);
+ }
+
+ public InvalidModuleException(String message, Throwable throwable) {
+ super("[Module] " + message, throwable);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/ex/InvalidModuleInfoException.java b/src/main/java/me/hulipvp/hcf/api/modules/ex/InvalidModuleInfoException.java
new file mode 100644
index 0000000..0afc729
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/ex/InvalidModuleInfoException.java
@@ -0,0 +1,16 @@
+package me.hulipvp.hcf.api.modules.ex;
+
+public class InvalidModuleInfoException extends Exception {
+
+ public InvalidModuleInfoException(String module) {
+ super("[Module] Module '" + module + "' has an invalid info.yml file.");
+ }
+
+ public InvalidModuleInfoException(Throwable throwable) {
+ super(throwable);
+ }
+
+ public InvalidModuleInfoException(String message, Throwable throwable) {
+ super("[Module] " + message, throwable);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/ex/InvalidModuleLoaderException.java b/src/main/java/me/hulipvp/hcf/api/modules/ex/InvalidModuleLoaderException.java
new file mode 100644
index 0000000..d592588
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/ex/InvalidModuleLoaderException.java
@@ -0,0 +1,8 @@
+package me.hulipvp.hcf.api.modules.ex;
+
+public class InvalidModuleLoaderException extends RuntimeException {
+
+ public InvalidModuleLoaderException(String module) {
+ super("[Module] Module '" + module + "' failed to be instated due to an invalid class loader");
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/api/modules/ex/ModuleLoadException.java b/src/main/java/me/hulipvp/hcf/api/modules/ex/ModuleLoadException.java
new file mode 100644
index 0000000..5dc65a5
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/api/modules/ex/ModuleLoadException.java
@@ -0,0 +1,8 @@
+package me.hulipvp.hcf.api.modules.ex;
+
+public class ModuleLoadException extends RuntimeException {
+
+ public ModuleLoadException(String module, String message) {
+ super("[Module] Failed to load Module '" + module + "', error: " + message);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/BackendType.java b/src/main/java/me/hulipvp/hcf/backend/BackendType.java
new file mode 100644
index 0000000..47ac175
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/BackendType.java
@@ -0,0 +1,29 @@
+package me.hulipvp.hcf.backend;
+
+import lombok.Getter;
+
+public enum BackendType {
+
+ REDIS("Redis"),
+ MONGO("Mongo");
+
+ @Getter private static BackendType fallback = BackendType.MONGO;
+
+ @Getter private String verboseName;
+
+ BackendType(String verboseName) {
+ this.verboseName = verboseName;
+ }
+
+ public static BackendType getOrDefault(String match) {
+ if(match == null)
+ return getFallback();
+
+ for(BackendType type : values()) {
+ if(type.getVerboseName().toLowerCase().equals(match.toLowerCase()))
+ return type;
+ }
+
+ return getFallback();
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/BackendUtils.java b/src/main/java/me/hulipvp/hcf/backend/BackendUtils.java
new file mode 100644
index 0000000..e4e7141
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/BackendUtils.java
@@ -0,0 +1,254 @@
+package me.hulipvp.hcf.backend;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestZone;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestZoneType;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.event.koth.data.KothPoint;
+import me.hulipvp.hcf.game.event.koth.data.KothTime;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import me.hulipvp.hcf.game.event.mountain.type.MountainType;
+import me.hulipvp.hcf.game.faction.Claim;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.game.faction.type.event.ConquestFaction;
+import me.hulipvp.hcf.game.faction.type.event.KothFaction;
+import me.hulipvp.hcf.game.faction.type.event.MountainFaction;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.faction.type.system.RoadFaction;
+import me.hulipvp.hcf.game.faction.type.system.SafezoneFaction;
+import me.hulipvp.hcf.game.faction.type.system.SystemFaction;
+import me.hulipvp.hcf.game.faction.type.system.WarzoneFaction;
+import me.hulipvp.hcf.utils.LocUtils;
+import me.hulipvp.hcf.utils.TaskUtils;
+import me.hulipvp.hcf.utils.TimeUtils;
+import me.hulipvp.hcf.api.chat.C;
+import org.bson.Document;
+import org.bukkit.ChatColor;
+
+import java.util.*;
+
+public class BackendUtils {
+
+ public static Faction factionFromDocument(Document doc) {
+ FactionType type = FactionType.valueOf(doc.getString("type"));
+
+ Faction faction;
+ switch(type) {
+ case PLAYER:
+ PlayerFaction pf = new PlayerFaction(UUID.fromString(doc.getString("uuid")), doc.getString("name"), null);
+
+ pf.setDeathban(doc.getBoolean("deathban"));
+ pf.setDtr(doc.getDouble("dtr"));
+
+ if(doc.getString("startRegen") != null)
+ pf.setStartRegen(TimeUtils.deserializeTimestamp(doc.getString("startRegen")));
+
+ if(doc.get("open") != null)
+ pf.setOpen(doc.getBoolean("open"));
+
+ pf.setRegening(doc.getBoolean("regening"));
+ pf.setLives(doc.getInteger("lives"));
+ pf.setBalance(doc.getInteger("balance"));
+ pf.setPowerFaction(doc.getBoolean("powerfaction"));
+ pf.setAnnouncement(doc.getString("announcement"));
+
+ if(doc.get("home") != null)
+ pf.setHome(LocUtils.stringToLocation(doc.getString("home")));
+
+ if(doc.get("kothCaptures") != null)
+ pf.setKothCaptures(doc.getInteger("kothCaptures"));
+
+ if(doc.get("members") != null) {
+ Document members = doc.get("members", Document.class);
+ for(String member : members.keySet()) {
+ FactionMember facMember = new FactionMember(UUID.fromString(member), FactionRank.valueOf(members.getString(member)));
+ if(facMember.getRank() == FactionRank.LEADER)
+ pf.setLeader(facMember);
+
+ pf.addMember(facMember);
+ }
+ }
+
+ if(doc.get("allies") != null) {
+ ArrayList allies = doc.get("allies", ArrayList.class);
+ for(String ally : allies)
+ pf.addAlly(UUID.fromString(ally));
+ }
+
+ if(doc.get("requestedAllies") != null) {
+ ArrayList requestedAllies = doc.get("requestedAllies", ArrayList.class);
+ for(String requestedAlly : requestedAllies)
+ pf.addRequestedAlly(UUID.fromString(requestedAlly));
+ }
+
+ if(doc.get("invited") != null) {
+ ArrayList invited = doc.get("invited", ArrayList.class);
+ for(String invitee : invited)
+ pf.addInvite(UUID.fromString(invitee));
+ }
+
+ if(doc.getString("claim") != null)
+ pf.addClaim(Claim.fromString(doc.getString("claim")));
+ faction = pf;
+ break;
+ case SAFEZONE:
+ SafezoneFaction safezone = new SafezoneFaction(UUID.fromString(doc.getString("uuid")), doc.getString("name"));
+ safezone.setDeathban(doc.getBoolean("deathban"));
+ safezone.setColor(ChatColor.valueOf(doc.getString("color")));
+
+ if(doc.get("home") != null)
+ safezone.setHome(LocUtils.stringToLocation(doc.getString("home")));
+
+ if(doc.getString("claim") != null)
+ safezone.addClaim(Claim.fromString(doc.getString("claim")));
+ faction = safezone;
+ break;
+ case WARZONE:
+ WarzoneFaction warzone = new WarzoneFaction(UUID.fromString(doc.getString("uuid")));
+ warzone.setDeathban(doc.getBoolean("deathban"));
+ warzone.setColor(ChatColor.valueOf(doc.getString("color")));
+
+ if(doc.get("home") != null)
+ warzone.setHome(LocUtils.stringToLocation(doc.getString("home")));
+
+ if(doc.getString("claim") != null)
+ warzone.addClaim(Claim.fromString(doc.getString("claim")));
+ faction = warzone;
+ break;
+ case KOTH:
+ KothFaction koth = new KothFaction(UUID.fromString(doc.getString("uuid")), doc.getString("name"), Koth.getKoth(doc.getString("koth")));
+ koth.setDeathban(doc.getBoolean("deathban"));
+ koth.setColor(ChatColor.valueOf(doc.getString("color")));
+
+ if(doc.get("home") != null)
+ koth.setHome(LocUtils.stringToLocation(doc.getString("home")));
+
+ if(doc.getString("claim") != null)
+ koth.addClaim(Claim.fromString(doc.getString("claim")));
+ faction = koth;
+ break;
+ case CONQUEST:
+ ConquestFaction conquest = new ConquestFaction(UUID.fromString(doc.getString("uuid")), doc.getString("name"), Conquest.getConquest(doc.getString("conquest")));
+ conquest.setDeathban(doc.getBoolean("deathban"));
+ conquest.setColor(ChatColor.valueOf(doc.getString("color")));
+
+ if(doc.get("home") != null) conquest.setHome(LocUtils.stringToLocation(doc.getString("home")));
+
+ if(doc.getString("claim") != null)
+ conquest.addClaim(Claim.fromString(doc.getString("claim")));
+ faction = conquest;
+ break;
+ case ROAD:
+ RoadFaction road = new RoadFaction(UUID.fromString(doc.getString("uuid")), doc.getString("name"));
+ road.setDeathban(doc.getBoolean("deathban"));
+ road.setColor(ChatColor.valueOf(doc.getString("color")));
+
+ if(doc.get("home") != null)
+ road.setHome(LocUtils.stringToLocation(doc.getString("home")));
+
+ if(doc.getString("claim") != null)
+ road.addClaim(Claim.fromString(doc.getString("claim")));
+ faction = road;
+ break;
+ case SYSTEM:
+ SystemFaction system = new SystemFaction(UUID.fromString(doc.getString("uuid")), doc.getString("name"));
+ system.setDeathban(doc.getBoolean("deathban"));
+ system.setColor(ChatColor.valueOf(doc.getString("color")));
+
+ if(doc.get("home") != null)
+ system.setHome(LocUtils.stringToLocation(doc.getString("home")));
+
+ if(doc.getString("claim") != null)
+ system.addClaim(Claim.fromString(doc.getString("claim")));
+ faction = system;
+ break;
+ case MOUNTAIN:
+ MountainFaction mountain = new MountainFaction(UUID.fromString(doc.getString("uuid")), doc.getString("name"), Mountain.getMountain(doc.getString("name")));
+ mountain.setDeathban(doc.getBoolean("deathban"));
+ mountain.setColor(ChatColor.valueOf(doc.getString("color")));
+
+ if(doc.get("home") != null)
+ mountain.setHome(LocUtils.stringToLocation(doc.getString("home")));
+
+ if(doc.getString("claim") != null)
+ mountain.addClaim(Claim.fromString(doc.getString("claim")));
+ faction = mountain;
+ break;
+ default:
+ faction = null;
+ return null;
+ }
+
+ Set claims = null;
+ if(doc.containsKey("claims")) {
+ claims = new HashSet<>();
+ List claimList = (ArrayList) doc.get("claims", ArrayList.class);
+ for(Document document : claimList) {
+ if(document == null || !document.containsKey("claim"))
+ continue;
+
+ claims.add(Claim.fromString(document.getString("claim")));
+ }
+ }
+
+ if(faction != null && claims != null && !claims.isEmpty())
+ claims.forEach(faction::addClaim);
+
+ return null;
+ }
+
+ public static Koth kothFromDocument(Document doc) {
+ Koth koth = new Koth(doc.getString("name"));
+ if(doc.getString("point") != null)
+ koth.setPoint(KothPoint.fromString(doc.getString("point")));
+
+ if(HCF.getInstance().getConfig().getString("koth.special-times." + koth.getName().toLowerCase()) != null)
+ koth.setTime(KothTime.valueOf(HCF.getInstance().getConfig().getString("koth.special-times." + koth.getName().toLowerCase())));
+
+ koth.setSpecial(doc.getBoolean("special"));
+ return koth;
+ }
+
+ public static Conquest conquestFromDocument(Document doc) {
+ Conquest conquest = new Conquest(doc.getString("name"));
+
+ if(doc.getString("red") != null)
+ conquest.getZones().put(ConquestZoneType.RED, ConquestZone.fromString(C.strip(doc.getString("red")).toUpperCase()));
+ if(doc.getString("yellow") != null)
+ conquest.getZones().put(ConquestZoneType.YELLOW, ConquestZone.fromString(C.strip(doc.getString("yellow")).toUpperCase()));
+ if(doc.getString("green") != null)
+ conquest.getZones().put(ConquestZoneType.GREEN, ConquestZone.fromString(C.strip(doc.getString("green")).toUpperCase()));
+ if(doc.getString("blue") != null)
+ conquest.getZones().put(ConquestZoneType.BLUE, ConquestZone.fromString(C.strip(doc.getString("blue")).toUpperCase()));
+
+ return conquest;
+ }
+
+ public static Mountain mountainFromDocument(Document doc) {
+ Mountain mountain = new Mountain(doc.getString("name"), MountainType.valueOf(doc.getString("type")));
+ mountain.setResetTime(doc.getInteger("resetTime"));
+
+ if(doc.getString("point1") != null)
+ mountain.setPoint1(LocUtils.stringToLocation(doc.getString("point1")));
+
+ if(doc.getString("point2") != null)
+ mountain.setPoint2(LocUtils.stringToLocation(doc.getString("point2")));
+
+ return mountain;
+ }
+
+ public static void invalidFactionCheck() {
+ TaskUtils.runAsync(() -> {
+ Faction.getFactions().values().stream()
+ .filter(PlayerFaction.class::isInstance)
+ .map(PlayerFaction.class::cast)
+ .forEach(playerFaction -> {
+ playerFaction.getAllies().removeIf(Faction::isNotAFaction);
+ });
+ });
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/HCFBackend.java b/src/main/java/me/hulipvp/hcf/backend/HCFBackend.java
new file mode 100644
index 0000000..409c7f4
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/HCFBackend.java
@@ -0,0 +1,27 @@
+package me.hulipvp.hcf.backend;
+
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.HCF;
+
+public abstract class HCFBackend implements IBackend {
+
+ @Getter private final BackendType type;
+
+ @Getter @Setter private boolean loaded;
+
+ public HCFBackend(BackendType type) {
+ this.type = type;
+ }
+
+ protected void logInfoMessage(String message) {
+ HCF.getInstance().getLogger().info("(Backend) {" + this.getType().getVerboseName() + "} - " + message);
+ }
+
+ protected void logException(String message, Exception e) {
+ HCF.getInstance().getLogger().severe("(Backend) {" + this.getType().getVerboseName() + "} - " + message);
+ HCF.getInstance().getLogger().severe("-------------------------------------------");
+ e.printStackTrace();
+ HCF.getInstance().getLogger().severe("-------------------------------------------");
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/IBackend.java b/src/main/java/me/hulipvp/hcf/backend/IBackend.java
new file mode 100644
index 0000000..26a2b08
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/IBackend.java
@@ -0,0 +1,81 @@
+package me.hulipvp.hcf.backend;
+
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+
+public interface IBackend {
+
+ /**
+ * Called when the plugin is being disabled.
+ */
+ void close();
+
+ // Profile //
+ void createProfile(HCFProfile profile);
+
+ void deleteProfile(HCFProfile profile);
+
+ void deleteProfiles();
+
+ void saveProfile(HCFProfile profile);
+
+ void saveProfileSync(HCFProfile profile);
+
+ void loadProfile(HCFProfile profile);
+
+ void loadProfiles();
+ // End Profile //
+
+ // Factions //
+ void createFaction(Faction faction);
+
+ void deleteFaction(Faction faction);
+
+ void deleteFactions();
+
+ void saveFaction(Faction faction);
+
+ void saveFactionSync(Faction faction);
+
+ void loadFactions();
+ // End Factions //
+
+ // Koths //
+ void createKoth(Koth koth);
+
+ void deleteKoth(Koth koth);
+
+ void saveKoth(Koth koth);
+
+ void saveKothSync(Koth koth);
+
+ void loadKoths();
+ // End Koths //
+
+ // Conquests //
+ void createConquest(Conquest conquest);
+
+ void deleteConquest(Conquest conquest);
+
+ void saveConquest(Conquest conquest);
+
+ void saveConquestSync(Conquest conquest);
+
+ void loadConquests();
+ // End Conquests //
+
+ // Mountains //
+ void createMountain(Mountain mountain);
+
+ void deleteMountain(Mountain mountain);
+
+ void saveMountain(Mountain mountain);
+
+ void saveMountainSync(Mountain mountain);
+
+ void loadMountains();
+ // End Mountains //
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/backends/MongoBackend.java b/src/main/java/me/hulipvp/hcf/backend/backends/MongoBackend.java
new file mode 100644
index 0000000..12dcd3c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/backends/MongoBackend.java
@@ -0,0 +1,333 @@
+package me.hulipvp.hcf.backend.backends;
+
+import com.mongodb.MongoClient;
+import com.mongodb.MongoCredential;
+import com.mongodb.ServerAddress;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.backend.BackendType;
+import me.hulipvp.hcf.backend.BackendUtils;
+import me.hulipvp.hcf.backend.HCFBackend;
+import me.hulipvp.hcf.backend.IBackend;
+import me.hulipvp.hcf.backend.creds.MongoCredentials;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.game.faction.type.event.ConquestFaction;
+import me.hulipvp.hcf.game.faction.type.event.KothFaction;
+import me.hulipvp.hcf.game.faction.type.event.MountainFaction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.TaskUtils;
+import org.bson.Document;
+import org.bukkit.Bukkit;
+
+import java.util.Collections;
+import java.util.UUID;
+
+import static com.mongodb.client.model.Filters.eq;
+
+public class MongoBackend extends HCFBackend implements IBackend {
+
+ private MongoClient mongo;
+ private MongoDatabase db;
+ private MongoCollection profiles, factions, koths, conquests, mountains;
+
+ public MongoBackend(MongoCredentials credentials) {
+ super(BackendType.MONGO);
+
+ try {
+ ServerAddress address = new ServerAddress(credentials.getHostname(), credentials.getPort());
+
+ if(HCF.getInstance().getConfig().getBoolean("backend.mongo.auth.enable")) {
+ MongoCredential credential = MongoCredential.createCredential(credentials.getUsername(), credentials.getAuthDb(), credentials.getPassword().toCharArray());
+ this.mongo = new MongoClient(address, Collections.singletonList(credential));
+ } else {
+ this.mongo = new MongoClient(address);
+ }
+
+ this.db = this.mongo.getDatabase(credentials.getDatabase());
+ this.profiles = this.db.getCollection("profiles");
+ this.factions = this.db.getCollection("factions");
+ this.koths = this.db.getCollection("koths");
+ this.conquests = this.db.getCollection("conquests");
+ this.mountains = this.db.getCollection("mountains");
+
+ this.logInfoMessage("Mongo Driver successfully loaded.");
+ setLoaded(true);
+ } catch(Exception e) {
+ this.logException("Mongo Driver failed to load.", e);
+ }
+ }
+
+ @Override
+ public void close() {
+ if(this.mongo != null)
+ this.mongo.close();
+ }
+
+ /*=============================*/
+ // Profiles
+
+ @Override
+ public void createProfile(HCFProfile profile) {
+ TaskUtils.runAsync(() -> {
+ this.profiles.insertOne(profile.toDocument());
+ });
+ }
+
+ @Override
+ public void deleteProfile(HCFProfile profile) {
+ TaskUtils.runAsync(() -> {
+ this.profiles.deleteOne(eq("uuid", profile.getUuid().toString()));
+ });
+ }
+
+ @Override
+ public void deleteProfiles() {
+ TaskUtils.runAsync(() -> {
+ this.profiles.drop();
+ this.profiles = this.db.getCollection("profiles");
+ });
+ }
+
+ @Override
+ public void saveProfile(HCFProfile profile) {
+ TaskUtils.runAsync(() -> {
+ this.saveProfileSync(profile);
+ });
+ }
+
+ @Override
+ public void saveProfileSync(HCFProfile profile) {
+ Document doc = profile.toDocument();
+ this.profiles.findOneAndReplace(eq("uuid", profile.getUuid().toString()), doc);
+ }
+
+ @Override
+ public void loadProfile(HCFProfile profile) {
+ Document doc = this.profiles.find(eq("uuid", profile.getUuid().toString())).first();
+
+ if(doc != null) {
+ profile.load(doc);
+ } else {
+ this.createProfile(profile);
+ }
+ }
+
+ @Override
+ public void loadProfiles() {
+ for(Document doc : this.profiles.find()) {
+ if(!doc.containsKey("uuid"))
+ continue;
+
+ UUID uuid = UUID.fromString(doc.getString("uuid"));
+ HCFProfile.getByUuid(uuid);
+ }
+ }
+
+ /*=============================*/
+
+ /*=============================*/
+ // Factions
+
+ @Override
+ public void createFaction(Faction faction) {
+ TaskUtils.runAsync(() -> {
+ this.factions.insertOne(faction.toDocument());
+ });
+ }
+
+ @Override
+ public void deleteFaction(Faction faction) {
+ TaskUtils.runAsync(() -> {
+ this.factions.deleteOne(eq("uuid", faction.getUuid().toString()));
+ });
+ }
+
+ @Override
+ public void deleteFactions() {
+ TaskUtils.runAsync(() -> {
+ this.factions.drop();
+ this.factions = this.db.getCollection("factions");
+ });
+ }
+
+ @Override
+ public void saveFaction(Faction faction) {
+ TaskUtils.runAsync(() -> {
+ this.saveFactionSync(faction);
+ });
+ }
+
+ @Override
+ public void saveFactionSync(Faction faction) {
+ Document doc = faction.toDocument();
+ if(doc != null)
+ this.factions.findOneAndReplace(eq("uuid", faction.getUuid().toString()), doc);
+ }
+
+ private synchronized void loadFaction(Document doc) {
+ if(doc != null) {
+ Faction faction = BackendUtils.factionFromDocument(doc);
+ if(faction == null)
+ return;
+
+ if(faction.getType() == FactionType.KOTH)
+ Koth.getKoth(faction.getName()).setFaction((KothFaction) faction);
+
+ if(faction.getType() == FactionType.CONQUEST)
+ Conquest.getConquest(faction.getName()).setFaction((ConquestFaction) faction);
+
+ if(faction.getType() == FactionType.MOUNTAIN)
+ Mountain.getMountain(faction.getName()).setFaction((MountainFaction) faction);
+ }
+ }
+
+ @Override
+ public void loadFactions() {
+ TaskUtils.runAsync(() -> {
+ for(Document doc : this.factions.find())
+ this.loadFaction(doc);
+ });
+
+ BackendUtils.invalidFactionCheck();
+ }
+ /*=============================*/
+
+ /*=============================*/
+ // Koths
+
+ @Override
+ public void createKoth(Koth koth) {
+ TaskUtils.runAsync(() -> {
+ this.koths.insertOne(koth.toDocument());
+ });
+ }
+
+ @Override
+ public void deleteKoth(Koth koth) {
+ TaskUtils.runAsync(() -> {
+ this.koths.deleteOne(eq("name", koth.getName()));
+ });
+ }
+
+ @Override
+ public void saveKoth(Koth koth) {
+ TaskUtils.runAsync(() -> {
+ this.saveKothSync(koth);
+ });
+ }
+
+ @Override
+ public void saveKothSync(Koth koth) {
+ this.koths.findOneAndReplace(eq("name", koth.getName()), koth.toDocument());
+ }
+
+ private synchronized void loadKoth(Document doc) {
+ if(doc != null) {
+ Koth koth = BackendUtils.kothFromDocument(doc);
+ Koth.getKoths().put(koth.getName(), koth);
+ }
+ }
+
+ @Override
+ public void loadKoths() {
+ for(Document doc : this.koths.find())
+ this.loadKoth(doc);
+ }
+ /*=============================*/
+
+ /*=============================*/
+ // Conquests
+
+ @Override
+ public void createConquest(Conquest conquest) {
+ TaskUtils.runAsync(() -> {
+ this.conquests.insertOne(conquest.toDocument());
+ });
+ }
+
+ @Override
+ public void deleteConquest(Conquest conquest) {
+ TaskUtils.runAsync(() -> {
+ this.conquests.deleteOne(eq("name", conquest.getName()));
+ });
+ }
+
+ @Override
+ public void saveConquest(Conquest conquest) {
+ TaskUtils.runAsync(() -> {
+ this.saveConquestSync(conquest);
+ });
+ }
+
+ @Override
+ public void saveConquestSync(Conquest conquest) {
+ this.conquests.findOneAndReplace(eq("name", conquest.getName()), conquest.toDocument());
+ }
+
+ private synchronized void loadConquest(Document doc) {
+ if(doc != null) {
+ Conquest conquest = BackendUtils.conquestFromDocument(doc);
+ Conquest.getConquests().put(conquest.getName(), conquest);
+ }
+ }
+
+ @Override
+ public void loadConquests() {
+ for(Document doc : this.conquests.find())
+ this.loadConquest(doc);
+ }
+ /*=============================*/
+
+ /*=============================*/
+ // Mountains
+
+ @Override
+ public void createMountain(Mountain mountain) {
+ TaskUtils.runAsync(() -> {
+ this.mountains.insertOne(mountain.toDocument());
+ });
+ }
+
+ @Override
+ public void deleteMountain(Mountain mountain) {
+ TaskUtils.runAsync(() -> {
+ this.mountains.deleteOne(eq("name", mountain.getName()));
+ });
+ }
+
+ @Override
+ public void saveMountain(Mountain mountain) {
+ TaskUtils.runAsync(() -> {
+ this.saveMountainSync(mountain);
+ });
+ }
+
+ @Override
+ public void saveMountainSync(Mountain mountain) {
+ try {
+ this.mountains.findOneAndReplace(eq("name", mountain.getName()), mountain.toDocument());
+ } catch(Exception ex) {
+ deleteMountain(mountain);
+ }
+ }
+
+ private synchronized void loadMountain(Document doc) {
+ if(doc != null) {
+ Mountain mountain = BackendUtils.mountainFromDocument(doc);
+ Mountain.getMountains().put(mountain.getName(), mountain);
+ }
+ }
+
+ @Override
+ public void loadMountains() {
+ for(Document doc : this.mountains.find())
+ this.loadMountain(doc);
+ }
+ /*=============================*/
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/backends/RedisBackend.java b/src/main/java/me/hulipvp/hcf/backend/backends/RedisBackend.java
new file mode 100644
index 0000000..0287d75
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/backends/RedisBackend.java
@@ -0,0 +1,381 @@
+package me.hulipvp.hcf.backend.backends;
+
+import lombok.Getter;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.backend.BackendType;
+import me.hulipvp.hcf.backend.BackendUtils;
+import me.hulipvp.hcf.backend.HCFBackend;
+import me.hulipvp.hcf.backend.creds.RedisCredentials;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.game.faction.type.event.ConquestFaction;
+import me.hulipvp.hcf.game.faction.type.event.KothFaction;
+import me.hulipvp.hcf.game.faction.type.event.MountainFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.TaskUtils;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.bson.Document;
+import org.bukkit.Bukkit;
+import redis.clients.jedis.Jedis;
+import redis.clients.jedis.JedisPool;
+
+import java.util.Set;
+import java.util.UUID;
+
+public class RedisBackend extends HCFBackend {
+
+ @Getter private JedisPool pool;
+
+ public RedisBackend(RedisCredentials credentials) {
+ super(BackendType.REDIS);
+
+ if(!credentials.password()) {
+ this.pool = new JedisPool(new GenericObjectPoolConfig(), credentials.getHost(), credentials.getPort(), 3000);
+ } else {
+ this.pool = new JedisPool(new GenericObjectPoolConfig(), credentials.getHost(), credentials.getPort(), 3000, credentials.getPassword());
+ }
+
+ try(Jedis jedis = pool.getResource()) {
+ setLoaded(jedis.isConnected());
+ if(isLoaded())
+ logInfoMessage("Redis Driver successfully loaded.");
+ else
+ throw new Exception("Unable to establish Jedis connection.");
+ } catch(Exception ex) {
+ logException("Redis Driver failed to load.", ex);
+ }
+ }
+
+ @Override
+ public void close() {
+ if(this.pool != null)
+ if(!this.pool.isClosed())
+ this.pool.close();
+ }
+
+ /*=============================*/
+ // Profiles
+
+ @Override
+ public void createProfile(HCFProfile profile) {
+ this.saveProfile(profile);
+ }
+
+ @Override
+ public void deleteProfile(HCFProfile profile) {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.del(this.getKey(KeyType.PROFILE, profile.getUuid().toString()));
+ }
+ }
+
+ @Override
+ public void deleteProfiles() {
+ TaskUtils.runAsync(() -> {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.del(this.getKey(KeyType.PROFILE) + "*");
+ }
+ });
+ }
+
+ @Override
+ public void saveProfile(HCFProfile profile) {
+ TaskUtils.runAsync(() -> {
+ this.saveProfileSync(profile);
+ });
+ }
+
+ @Override
+ public void saveProfileSync(HCFProfile profile) {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.set(this.getKey(KeyType.PROFILE, profile.getUuid().toString()), profile.toDocument().toJson());
+ }
+ }
+
+ @Override
+ public void loadProfile(HCFProfile profile) {
+ try(Jedis jedis = this.getPool().getResource()) {
+ String json = jedis.get(this.getKey(KeyType.PROFILE, profile.getUuid().toString()));
+
+ if(json != null) {
+ Document doc = Document.parse(json);
+ profile.load(doc);
+ } else {
+ this.createProfile(profile);
+ }
+ }
+ }
+
+ @Override
+ public void loadProfiles() {
+ try(Jedis jedis = this.getPool().getResource()) {
+ Set profiles = jedis.keys(this.getKey(KeyType.PROFILE) + "*");
+
+ profiles.forEach(profile -> {
+ Document doc = Document.parse(jedis.get(profile));
+ if(doc == null || !doc.containsKey("uuid"))
+ return;
+
+ UUID uuid = UUID.fromString(doc.getString("uuid"));
+ HCFProfile.getByUuid(uuid);
+ });
+ }
+ }
+
+ /*=============================*/
+
+ /*=============================*/
+ // Factions
+
+ @Override
+ public void createFaction(Faction faction) {
+ this.saveFaction(faction);
+ }
+
+ @Override
+ public void deleteFaction(Faction faction) {
+ TaskUtils.runAsync(() -> {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.del(this.getKey(KeyType.FACTION, faction.getUuid().toString()));
+ }
+ });
+ }
+
+ @Override
+ public void deleteFactions() {
+ TaskUtils.runAsync(() -> {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.del(this.getKey(KeyType.FACTION) + "*");
+ }
+ });
+ }
+
+ @Override
+ public void saveFaction(Faction faction) {
+ TaskUtils.runAsync(() -> {
+ this.saveFactionSync(faction);
+ });
+ }
+
+ @Override
+ public void saveFactionSync(Faction faction) {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.set(this.getKey(KeyType.FACTION, faction.getUuid().toString()), faction.toDocument().toJson());
+ }
+ }
+
+ private synchronized void loadFaction(Document doc) {
+ if(doc != null) {
+ Faction faction = BackendUtils.factionFromDocument(doc);
+ if(faction == null)
+ return;
+
+ if(faction.getType() == FactionType.KOTH)
+ Koth.getKoth(faction.getName()).setFaction((KothFaction) faction);
+
+ if(faction.getType() == FactionType.CONQUEST)
+ Conquest.getConquest(faction.getName()).setFaction((ConquestFaction) faction);
+
+ if(faction.getType() == FactionType.MOUNTAIN)
+ Mountain.getMountain(faction.getName()).setFaction((MountainFaction) faction);
+ }
+ }
+
+ @Override
+ public void loadFactions() {
+ try(Jedis jedis = this.getPool().getResource()) {
+ Set factions = jedis.keys(this.getKey(KeyType.FACTION) + "*");
+
+ factions.forEach(faction -> {
+ Document doc = Document.parse(jedis.get(faction));
+ if(doc != null)
+ this.loadFaction(doc);
+ });
+ }
+
+ BackendUtils.invalidFactionCheck();
+ }
+ /*=============================*/
+
+ /*=============================*/
+ // Koths
+
+ @Override
+ public void createKoth(Koth koth) {
+ this.saveKoth(koth);
+ }
+
+ @Override
+ public void deleteKoth(Koth koth) {
+ TaskUtils.runAsync(() -> {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.del(this.getKey(KeyType.KOTH, koth.getName()));
+ }
+ });
+ }
+
+ @Override
+ public void saveKoth(Koth koth) {
+ TaskUtils.runAsync(() -> {
+ this.saveKothSync(koth);
+ });
+ }
+
+ @Override
+ public void saveKothSync(Koth koth) {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.set(this.getKey(KeyType.KOTH, koth.getName()), koth.toDocument().toJson());
+ }
+ }
+
+ private synchronized void loadKoth(Document doc) {
+ if(doc != null) {
+ Koth koth = BackendUtils.kothFromDocument(doc);
+ Koth.getKoths().put(koth.getName(), koth);
+ }
+ }
+
+ @Override
+ public void loadKoths() {
+ try(Jedis jedis = this.getPool().getResource()) {
+ Set koths = jedis.keys(this.getKey(KeyType.KOTH) + "*");
+
+ koths.forEach(koth -> {
+ Document doc = Document.parse(jedis.get(koth));
+ if(doc != null)
+ this.loadKoth(doc);
+ });
+ }
+ }
+ /*=============================*/
+
+ /*=============================*/
+ // Conquests
+
+ @Override
+ public void createConquest(Conquest conquest) {
+ this.saveConquest(conquest);
+ }
+
+ @Override
+ public void deleteConquest(Conquest conquest) {
+ TaskUtils.runAsync(() -> {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.del(this.getKey(KeyType.CONQUEST, conquest.getName()));
+ }
+ });
+ }
+
+ @Override
+ public void saveConquest(Conquest conquest) {
+ TaskUtils.runAsync(() -> {
+ this.saveConquestSync(conquest);
+ });
+ }
+
+ @Override
+ public void saveConquestSync(Conquest conquest) {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.set(this.getKey(KeyType.CONQUEST, conquest.getName()), conquest.toDocument().toJson());
+ }
+ }
+
+ private synchronized void loadConquest(Document doc) {
+ if(doc != null) {
+ Conquest conquest = BackendUtils.conquestFromDocument(doc);
+ Conquest.getConquests().put(conquest.getName(), conquest);
+ }
+ }
+
+ @Override
+ public void loadConquests() {
+ try(Jedis jedis = this.getPool().getResource()) {
+ Set conquests = jedis.keys(this.getKey(KeyType.CONQUEST) + "*");
+
+ conquests.forEach(conquest -> {
+ Document doc = Document.parse(jedis.get(conquest));
+ if(doc != null)
+ this.loadConquest(doc);
+ });
+ }
+ }
+ /*=============================*/
+
+ /*=============================*/
+ // Mountains
+
+ @Override
+ public void createMountain(Mountain mountain) {
+ this.saveMountain(mountain);
+ }
+
+ @Override
+ public void deleteMountain(Mountain mountain) {
+ TaskUtils.runAsync(() -> {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.del(this.getKey(KeyType.MOUNTAIN, mountain.getName()));
+ }
+ });
+ }
+
+ @Override
+ public void saveMountain(Mountain mountain) {
+ TaskUtils.runAsync(() -> {
+ this.saveMountainSync(mountain);
+ });
+ }
+
+ @Override
+ public void saveMountainSync(Mountain mountain) {
+ try(Jedis jedis = this.getPool().getResource()) {
+ jedis.set(this.getKey(KeyType.MOUNTAIN, mountain.getName()), mountain.toDocument().toJson());
+ }
+ }
+
+ private synchronized void loadMountain(Document doc) {
+ if(doc != null) {
+ Mountain mountain = BackendUtils.mountainFromDocument(doc);
+ Mountain.getMountains().put(mountain.getName(), mountain);
+ }
+ }
+
+ @Override
+ public void loadMountains() {
+ try(Jedis jedis = this.getPool().getResource()) {
+ Set mountains = jedis.keys(this.getKey(KeyType.MOUNTAIN) + "*");
+
+ mountains.forEach(mountain -> {
+ Document doc = Document.parse(jedis.get(mountain));
+ if(doc != null)
+ this.loadMountain(doc);
+ });
+ }
+ }
+ /*=============================*/
+
+ private String getKey(KeyType type) {
+ return "hcf:map" + ConfigValues.MAP_NUMBER + ":" + type.getPrefix() + ":";
+ }
+
+ private String getKey(KeyType type, String identifier) {
+ return getKey(type) + identifier;
+ }
+
+ private enum KeyType {
+
+ PROFILE("profile"),
+ FACTION("faction"),
+ KOTH("koth"),
+ CONQUEST("conquest"),
+ MOUNTAIN("mountain");
+
+ @Getter private String prefix;
+
+ KeyType(String prefix) {
+ this.prefix = prefix;
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/creds/MongoCredentials.java b/src/main/java/me/hulipvp/hcf/backend/creds/MongoCredentials.java
new file mode 100644
index 0000000..77fe755
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/creds/MongoCredentials.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.backend.creds;
+
+import lombok.Getter;
+import me.hulipvp.hcf.utils.ConfigValues;
+
+public class MongoCredentials {
+
+ @Getter private final String hostname, username, password, database, authDb;
+ @Getter private final int port;
+
+ public MongoCredentials(String hostname, int port, String username, String password, String database, String authDb) {
+ this.hostname = hostname;
+ this.port = port;
+ this.username = username;
+ this.password = password;
+ this.database = database + (database.endsWith(ConfigValues.MAP_NUMBER + "") ? "" : ConfigValues.MAP_NUMBER);
+ this.authDb = authDb;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/creds/RedisCredentials.java b/src/main/java/me/hulipvp/hcf/backend/creds/RedisCredentials.java
new file mode 100644
index 0000000..4cdec85
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/creds/RedisCredentials.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.backend.creds;
+
+import lombok.Getter;
+
+public class RedisCredentials {
+
+ @Getter private final String host, password;
+ @Getter private final int port;
+
+ public RedisCredentials(String host, int port, String password) {
+ this.host = host;
+ this.port = port;
+ this.password = password;
+ }
+
+ public boolean password() {
+ return this.getPassword().length() > 0;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/files/ConfigFile.java b/src/main/java/me/hulipvp/hcf/backend/files/ConfigFile.java
new file mode 100644
index 0000000..efe8617
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/files/ConfigFile.java
@@ -0,0 +1,66 @@
+package me.hulipvp.hcf.backend.files;
+
+import me.hulipvp.hcf.HCF;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.io.IOException;
+
+public abstract class ConfigFile {
+
+ private File file;
+ public FileConfiguration config;
+
+ public ConfigFile(String name, HCF plugin) {
+ name += (name.endsWith(".yml") ? "" : ".yml");
+
+ file = new File(plugin.getDataFolder() + File.separator + name);
+ if(!file.exists()) {
+ try {
+ plugin.getLogger().info(name + " doesn't exist, now creating...");
+
+ file.getParentFile().mkdirs();
+ if(plugin.getResource(name) != null) {
+ plugin.saveResource(name, false);
+ HCF.getInstance().getLogger().info("Successfully created " + file + ".");
+ } else {
+ if(file.createNewFile())
+ HCF.getInstance().getLogger().info("Successfully created " + file + ".");
+ }
+
+ plugin.getLogger().info(name + " has successfully been created");
+ } catch(IOException ex) {
+ plugin.getLogger().severe(name + " wasn't able to be created: " + ex.getMessage());
+ ex.printStackTrace();
+ }
+ }
+
+ this.config = YamlConfiguration.loadConfiguration(this.file);
+ }
+
+ public ConfigFile(String name) {
+ this(name, HCF.getInstance());
+ }
+
+ public File getFile() {
+ return this.file;
+ }
+
+ public FileConfiguration getConfig() {
+ return this.config;
+ }
+
+ public boolean save() {
+ try {
+ this.getConfig().save(this.getFile());
+ return true;
+ } catch(IOException ignored) { }
+
+ return false;
+ }
+
+ public void reload() {
+ this.config = YamlConfiguration.loadConfiguration(this.file);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/backend/files/KitsFile.java b/src/main/java/me/hulipvp/hcf/backend/files/KitsFile.java
new file mode 100644
index 0000000..02effc6
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/files/KitsFile.java
@@ -0,0 +1,112 @@
+package me.hulipvp.hcf.backend.files;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.kits.Kit;
+import me.hulipvp.hcf.game.kits.MapKit;
+import me.hulipvp.hcf.game.player.data.PlayerInv;
+import me.hulipvp.hcf.utils.item.InvUtils;
+import me.hulipvp.hcf.utils.StringUtils;
+import org.bukkit.ChatColor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class KitsFile extends ConfigFile {
+
+ @Getter private Map kits = new HashMap<>();
+
+ public KitsFile() {
+ super("kits.yml");
+ }
+
+ public void init() {
+ if(!config.contains("kits")) {
+ config.createSection("kits");
+ save();
+ return;
+ }
+
+ for(String kit : config.getConfigurationSection("kits").getKeys(false)) {
+ PlayerInv playerInv = InvUtils.invFromString(config.getString("kits." + kit + ".inv"));
+ ChatColor color = ChatColor.valueOf(config.getString("kits." + kit + ".color"));
+ boolean enabled = config.getBoolean("kits." + kit + ".enabled");
+
+ MapKit mapKit = new MapKit(kit);
+ mapKit.setPlayerInv(playerInv);
+ mapKit.setColor(color);
+ mapKit.setEnabled(enabled);
+
+ kits.put(kit, mapKit);
+ }
+ }
+
+ public MapKit getKit(String kit) {
+ return kits.get(kit);
+ }
+
+ public void saveKit(MapKit kit) {
+ config.set("kits." + kit.getName() + ".inv", kit.getPlayerInv().toString());
+ config.set("kits." + kit.getName() + ".color", kit.getColor().name());
+ config.set("kits." + kit.getName() + ".enabled", kit.isEnabled());
+ }
+
+ public void saveKits() {
+ getKits().values().forEach(this::saveKit);
+
+ this.save();
+ }
+
+ public boolean isValidKit(String kit) {
+ return getKit(kit) != null;
+ }
+
+ public void setEnabled(String kit, boolean enabled) {
+ if(isValidKit(kit)) {
+ getKit(kit).setEnabled(enabled);
+ }
+
+ config.set("kits." + kit + ".enabled", enabled);
+ this.save();
+ }
+
+ public boolean isEnabled(String kit) {
+ return getKit(kit).isEnabled();
+ }
+
+ public void setMapkitInv(String kit, PlayerInv playerInv) {
+ if(isValidKit(kit)) {
+ getKit(kit).setPlayerInv(playerInv);
+ }
+
+ config.set("kits." + kit + ".inv", playerInv.toString());
+ this.save();
+ }
+
+ public PlayerInv getMapkitInv(String kit) {
+ return getKit(kit).getPlayerInv();
+ }
+
+ public void setColor(String kit, ChatColor color) {
+ if(isValidKit(kit)) {
+ getKit(kit).setColor(color);
+ }
+
+ config.set("kits." + kit + ".color", StringUtils.chatColorToString(color));
+ this.save();
+ }
+
+ public ChatColor getColor(String kit) {
+ ChatColor color;
+ try {
+ color = ChatColor.valueOf(config.getString("kits." + kit + ".color"));
+ } catch(Exception ex) {
+ color = ChatColor.GREEN;
+ }
+
+ return color;
+ }
+
+ public String getDisplay(String kit) {
+ return getKit(kit).getDisplay();
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/files/LocationsFile.java b/src/main/java/me/hulipvp/hcf/backend/files/LocationsFile.java
new file mode 100644
index 0000000..642cb30
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/files/LocationsFile.java
@@ -0,0 +1,58 @@
+package me.hulipvp.hcf.backend.files;
+
+import lombok.Getter;
+import me.hulipvp.hcf.utils.LocUtils;
+import org.bukkit.Location;
+
+public class LocationsFile extends ConfigFile {
+
+ @Getter private Location endSpawn, endExit, netherSpawn, netherExit;
+
+ public LocationsFile() {
+ super("locations.yml");
+ }
+
+ public void init() {
+ String endSpawn = this.getConfig().getString("locations.end.spawn");
+ String endExit = this.getConfig().getString("locations.end.exit");
+ String netherSpawn = this.getConfig().getString("locations.nether.exit");
+ String netherExit = this.getConfig().getString("locations.nether.exit");
+
+ if(endSpawn != null)
+ this.endSpawn = (endSpawn.length() > 0) ? LocUtils.stringToLocation(endSpawn) : null;
+
+ if(endExit != null)
+ this.endExit = (endExit.length() > 0) ? LocUtils.stringToLocation(endExit) : null;
+
+ if(netherSpawn != null)
+ this.netherSpawn = (netherSpawn.length() > 0) ? LocUtils.stringToLocation(netherSpawn) : null;
+
+ if(netherExit != null)
+ this.netherExit = (netherExit.length() > 0) ? LocUtils.stringToLocation(netherExit) : null;
+ }
+
+ public void setEndSpawn( Location location) {
+ this.endSpawn = location;
+
+ this.getConfig().set("locations.end.spawn", LocUtils.locationToString(location));
+ }
+
+
+ public void setEndExit( Location location) {
+ this.endExit = location;
+
+ this.getConfig().set("locations.end.exit", LocUtils.locationToString(location));
+ }
+
+ public void setNetherSpawn( Location location) {
+ this.netherSpawn = location;
+
+ this.getConfig().set("locations.nether.spawn", LocUtils.locationToString(location));
+ }
+
+ public void setNetherExit( Location location) {
+ this.netherExit = location;
+
+ this.getConfig().set("locations.nether.exit", LocUtils.locationToString(location));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/files/MessagesFile.java b/src/main/java/me/hulipvp/hcf/backend/files/MessagesFile.java
new file mode 100644
index 0000000..b526d15
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/files/MessagesFile.java
@@ -0,0 +1,89 @@
+package me.hulipvp.hcf.backend.files;
+
+import me.hulipvp.hcf.api.chat.C;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class MessagesFile extends ConfigFile {
+
+ public MessagesFile() {
+ super("messages.yml");
+ }
+
+ public List getHelp() {
+ return this.getConfig().getStringList("help.main");
+ }
+
+ public List getCoords() {
+ return this.getConfig().getStringList("help.coords");
+ }
+
+ public List getFactionSubclaiming() {
+ return this.getConfig().getStringList("faction.help.subclaiming");
+ }
+
+ public List getFactionClaimingStart() {
+ return this.getConfig().getStringList("faction.help.claiming");
+ }
+
+ public List getFactionHelp() {
+ return this.getConfig().getStringList("faction.help.main");
+ }
+
+ public List getFactionCaptainHelp() {
+ return this.getConfig().getStringList("faction.help.captain");
+ }
+
+ public List getFactionColeaderHelp() {
+ return this.getConfig().getStringList("faction.help.coleader");
+ }
+
+ public List getPlayerFactionShow() {
+ return this.getConfig().getStringList("faction.show.player");
+ }
+
+ public List getSystemFactionShow() {
+ return this.getConfig().getStringList("faction.show.system");
+ }
+
+ public List getEconomyHelp() {
+ return this.getConfig().getStringList("help.economy");
+ }
+
+ public List getLivesHelp() {
+ return this.getConfig().getStringList("help.lives");
+ }
+
+ public List getPvpHelp() {
+ return this.getConfig().getStringList("help.pvp");
+ }
+
+ public List getFilterHelp() {
+ return this.getConfig().getStringList("help.filter");
+ }
+
+ public List getLff() {
+ return this.getConfig().getStringList("other.lff");
+ }
+
+ public List getShopBuyLines() {
+ return this.getConfig().getStringList("shop.lines.buy").stream()
+ .map(C::color).collect(Collectors.toList());
+ }
+
+ public List getShopSellLines() {
+ return this.getConfig().getStringList("shop.lines.sell").stream()
+ .map(C::color).collect(Collectors.toList());
+ }
+
+ public List getShopInsufficientLines() {
+ return this.getConfig().getStringList("shop.lines.insufficient").stream()
+ .map(C::color).collect(Collectors.toList());
+ }
+
+ public List getShopNoItemLines() {
+ return this.getConfig().getStringList("shop.lines.no-items").stream()
+ .map(C::color).collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/backend/files/ReclaimFile.java b/src/main/java/me/hulipvp/hcf/backend/files/ReclaimFile.java
new file mode 100644
index 0000000..c0b14b9
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/backend/files/ReclaimFile.java
@@ -0,0 +1,47 @@
+package me.hulipvp.hcf.backend.files;
+
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ReclaimFile extends ConfigFile {
+
+ @Getter private Map> groups;
+ @Getter private List reclaimed;
+
+ public ReclaimFile() {
+ super("reclaim.yml");
+
+ groups = new HashMap<>();
+ reclaimed = new ArrayList<>();
+ }
+
+ public void loadGroups() {
+ if(config.contains("reclaim")) {
+ for(String key : config.getConfigurationSection("reclaim").getKeys(false))
+ groups.put(key, config.getStringList("reclaim." + key + ".commands"));
+ } else {
+ config.createSection("reclaim");
+ save();
+ }
+ }
+
+ public void loadReclaimed() {
+ if(config.contains("reclaimed")) {
+ reclaimed = config.getStringList("reclaimed");
+ } else {
+ config.createSection("reclaimed");
+ save();
+ }
+ }
+
+ public void saveReclaimed() {
+ reload();
+ config.set("reclaimed", reclaimed);
+ save();
+ reload();
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/BalanceCommand.java b/src/main/java/me/hulipvp/hcf/commands/BalanceCommand.java
new file mode 100644
index 0000000..b63a0db
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/BalanceCommand.java
@@ -0,0 +1,30 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class BalanceCommand {
+
+ @Command(label = "balance", aliases = {"money", "$", "bal"}, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() != 1) {
+ p.sendMessage(Locale.COMMAND_BALANCE.toString().replaceAll("%balance%", String.valueOf(profile.getBalance())));
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(0));
+ if(target == null) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ return;
+ }
+
+ HCFProfile targetProfile = HCFProfile.getByPlayer(target);
+ p.sendMessage(Locale.COMMAND_BALANCE_OTHER.toString().replaceAll("%player%", target.getName()).replaceAll("%balance%", String.valueOf(targetProfile.getBalance())));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/BottleCommand.java b/src/main/java/me/hulipvp/hcf/commands/BottleCommand.java
new file mode 100644
index 0000000..47ac968
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/BottleCommand.java
@@ -0,0 +1,59 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.ExpUtils;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.item.ItemBuilder;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+public class BottleCommand {
+
+ @Command(label = "xpbottle", aliases = { "bottle" }, permission = "command.bottle", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player player = args.getPlayer();
+ int currentXp = ExpUtils.getTotalExperience(player);
+ if(currentXp <= 25) {
+ player.sendMessage(Locale.COMMAND_BOTTLE_NOT_ENOUGH.toString());
+ return;
+ }
+
+ if(player.getInventory().firstEmpty() == -1) {
+ player.sendMessage(Locale.COMMAND_BOTTLE_FULL_INVENTORY.toString());
+ return;
+ }
+
+ ExpUtils.setTotalExperience(player, 0);
+
+ player.getInventory().addItem(getXpBottle(currentXp, player.getName()));
+ player.sendMessage(Locale.COMMAND_BOTTLE_SUCCESS.toString().replace("%amount%", currentXp + ""));
+ }
+
+ public static ItemStack getXpBottle(int xpAmount, String enchanter) {
+ return new ItemBuilder(Material.EXP_BOTTLE)
+ .amount(1)
+ .name(C.color("&e&lXP Bottle &7(Throw)"))
+ .lore(
+ "&6Amount: " + xpAmount + " XP",
+ "&6Enchanter: " + enchanter
+ )
+ .get();
+ }
+
+ public static boolean isXpBottle(ItemStack item) {
+ return item != null && item.getType() == Material.EXP_BOTTLE
+ && item.hasItemMeta() && item.getItemMeta().hasDisplayName()
+ && item.getItemMeta().hasLore() && item.getItemMeta().getLore().get(0).contains("XP");
+ }
+
+ public static int getXpAmount(ItemStack item) {
+ try {
+ return Integer.parseInt(C.strip(item.getItemMeta().getLore().get(0).split(" ")[1].replace("XP", "")));
+ } catch(Exception err) {
+ return 0;
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/ChatCommand.java b/src/main/java/me/hulipvp/hcf/commands/ChatCommand.java
new file mode 100644
index 0000000..b964113
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/ChatCommand.java
@@ -0,0 +1,83 @@
+package me.hulipvp.hcf.commands;
+
+import com.google.common.base.Joiner;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class ChatCommand {
+
+ public static int slow = 0;
+ public static boolean muted = false;
+
+ @Command(label = "clearchat", aliases = { "cc", "chatclear" }, permission = "command.clearchat")
+ public void onClear(CommandData args) {
+ Bukkit.getOnlinePlayers().stream()
+ .filter(player -> !player.hasPermission("hcf.staff"))
+ .forEach(player -> {
+ for(int i = 0; i < 256; i++)
+ player.sendMessage(" ");
+ });
+
+ Bukkit.broadcastMessage(Locale.COMMAND_CHAT_CLEARED.toString());
+ }
+
+ @Command(label = "mutechat", aliases = { "mc", "umc", "chatmute", "unmutechat" }, permission = "command.mutechat")
+ public void onMute(CommandData args) {
+ muted = !muted;
+
+ if(muted)
+ Bukkit.broadcastMessage(Locale.COMMAND_CHAT_MUTED.toString());
+ else
+ Bukkit.broadcastMessage(Locale.COMMAND_CHAT_UNMUTED.toString());
+ }
+
+ @Command(label = "slowchat", aliases = { "slow", "unslow", "unslowchat" }, permission = "command.slowchat")
+ public void onSlow(CommandData args) {
+ if(args.getLabel().contains("unslow")) {
+ slow = 0;
+ Bukkit.broadcastMessage(Locale.COMMAND_CHAT_UNSLOWED.toString());
+ return;
+ }
+
+ if(args.length() < 1) {
+ args.getSender().sendMessage(C.color("&cUsage: /" + args.getLabel() + " "));
+ return;
+ }
+
+ if(!StringUtils.isInt(args.getArg(0))) {
+ args.getSender().sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", args.getArg(1)));
+ return;
+ }
+
+ slow = Integer.parseInt(args.getArg(0));
+
+ if(slow <= 0)
+ Bukkit.broadcastMessage(Locale.COMMAND_CHAT_UNSLOWED.toString());
+ else
+ Bukkit.broadcastMessage(Locale.COMMAND_CHAT_SLOWED.toString().replaceAll("%time%", slow + ""));
+ }
+
+ @Command(label = "sc", aliases = { "staffchat" }, permission = "command.staffchat", playerOnly = true)
+ public void onStaffChat(CommandData args) {
+ Player player = (Player) args.getSender();
+ if(args.length() == 0) {
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+ profile.setStaffChat(!profile.isStaffChat());
+ player.sendMessage(Locale.COMMAND_STAFF_CHAT_TOGGLED.toString().replace("%status%", C.color(profile.isStaffChat() ? "&aEnabled" : "&cDisabled")));
+ return;
+ }
+
+ String message = Joiner.on(' ').join(args.getArgs());
+ Bukkit.getOnlinePlayers().stream()
+ .filter(ply -> ply.hasPermission("hcf.staff"))
+ .forEach(ply -> {
+ ply.sendMessage(Locale.COMMAND_STAFF_CHAT_MESSAGE.toString().replace("%name%", player.getName()).replace("%message%", message));
+ });
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/CommandManager.java b/src/main/java/me/hulipvp/hcf/commands/CommandManager.java
new file mode 100644
index 0000000..ccc2615
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/CommandManager.java
@@ -0,0 +1,73 @@
+package me.hulipvp.hcf.commands;
+
+import lombok.Getter;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.event.conquest.command.ConquestCommand;
+import me.hulipvp.hcf.game.event.koth.command.KothCommand;
+import me.hulipvp.hcf.game.event.mountain.command.MountainCommand;
+import me.hulipvp.hcf.game.faction.command.FactionCommand;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.CommandAPI;
+
+public class CommandManager {
+
+ @Getter private CommandAPI commandApi;
+
+ public CommandManager() {
+ this.commandApi = new CommandAPI(HCF.getInstance(), "hcf", Locale.NO_PERMISSION.toString(), Locale.PLAYER_ONLY.toString(), Locale.COMMAND_NOT_FOUND.toString());
+ }
+
+ public void registerCommands() {
+ new FactionCommand().getArguments().forEach(this::registerCommands);
+
+ registerCommands(new BalanceCommand());
+ registerCommands(new BottleCommand());
+ registerCommands(new ChatCommand());
+ registerCommands(new ConquestCommand());
+ registerCommands(new CrowbarCommand());
+ registerCommands(new DebugHCFCommand());
+ registerCommands(new HCFCoreCommand());
+ registerCommands(new EconomyCommand());
+ registerCommands(new ItemCommand());
+ registerCommands(new LffCommand());
+ registerCommands(new EotwCommand());
+ registerCommands(new FilterCommand());
+ registerCommands(new FlyCommand());
+ registerCommands(new GamemodeCommand());
+ registerCommands(new HelpCommand());
+ registerCommands(new InstateHCFCommand());
+ registerCommands(new KothCommand());
+ registerCommands(new LivesCommand());
+ registerCommands(new LogoutCommand());
+ registerCommands(new MapkitCommand());
+ registerCommands(new MessageCommand());
+ registerCommands(new ModCommand());
+ registerCommands(new ModulesCommand());
+ registerCommands(new NotesCommand());
+ registerCommands(new MountainCommand());
+ registerCommands(new PayCommand());
+ registerCommands(new PingCommand());
+ registerCommands(new PvpCommand());
+ registerCommands(new ReclaimCommand());
+ registerCommands(new ResetDataCommand());
+ registerCommands(new RestoreInventoryCommand());
+ registerCommands(new SetCommand());
+ registerCommands(new SpawnCommand());
+ registerCommands(new SetMaxPlayersCommand());
+ registerCommands(new SettingsCommand());
+ registerCommands(new SotwCommand());
+ registerCommands(new StaffReviveCommand());
+ registerCommands(new StatsCommand());
+ registerCommands(new TeleportCommand());
+ registerCommands(new TimerCommand());
+ registerCommands(new ToggleChatCommand());
+ }
+
+ public void registerCommands(Object object) {
+ commandApi.registerCommands(object);
+ }
+
+ public void unregisterCommands(Object object) {
+ commandApi.unregisterCommands(object);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/CrowbarCommand.java b/src/main/java/me/hulipvp/hcf/commands/CrowbarCommand.java
new file mode 100644
index 0000000..1f687fd
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/CrowbarCommand.java
@@ -0,0 +1,39 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.listeners.CrowbarListener;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class CrowbarCommand {
+
+ @Command(label = "crowbar", permission = "command.crowbar")
+ public void onCommand(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ if(args.length() == 0) {
+ if(sender instanceof Player)
+ giveCrowbar((Player) sender);
+ else
+ sender.sendMessage(C.color("&cUsage: /crowbar "));
+ } else {
+ Player player = Bukkit.getPlayer(args.getArg(0));
+ if(player == null || !player.isOnline()) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ return;
+ }
+
+ giveCrowbar(player);
+ sender.sendMessage(C.color("&aGave '" + player.getName() + "' a crowbar."));
+ }
+ }
+
+ private void giveCrowbar(Player player) {
+ player.getInventory().addItem(CrowbarListener.getCrowbar());
+ player.updateInventory();
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/DebugHCFCommand.java b/src/main/java/me/hulipvp/hcf/commands/DebugHCFCommand.java
new file mode 100644
index 0000000..96db9b8
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/DebugHCFCommand.java
@@ -0,0 +1,58 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.TaskUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+
+public class DebugHCFCommand {
+
+ @Command(label = "debughcf", permission = "command.debug")
+ public void onCommand(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ sender.sendMessage(C.color(ConfigValues.SERVER_PRIMARY + "Debug Information:"));
+ sender.sendMessage(C.color(" &7-" + ConfigValues.SERVER_SECONDARY + " Online Players: &f") + Bukkit.getOnlinePlayers().size());
+ sender.sendMessage(C.color(" &7-" + ConfigValues.SERVER_SECONDARY + " TPS: &f") + Bukkit.spigot().getTPS()[0]);
+ sender.sendMessage(C.color(" &7-" + ConfigValues.SERVER_SECONDARY + " Backend Driver: &f") + HCF.getInstance().getBackend().getType().getVerboseName());
+ sender.sendMessage(C.color(" &7-" + ConfigValues.SERVER_SECONDARY + " Profiles: &f") + HCFProfile.getProfiles().size());
+ sender.sendMessage(C.color(" &7-" + ConfigValues.SERVER_SECONDARY + " Factions: &f") + Faction.getFactions().size());
+ sender.sendMessage(C.color(" &7-" + ConfigValues.SERVER_SECONDARY + " Koths: &f") + Koth.getKoths().size());
+ sender.sendMessage(C.color(" &7-" + ConfigValues.SERVER_SECONDARY + " Conquests: &f") + Conquest.getConquests().size());
+ sender.sendMessage(C.color(" &7-" + ConfigValues.SERVER_SECONDARY + " Mountains: &f") + Mountain.getMountains().size());
+
+ /*if(sender instanceof Player) {
+ HCFProfile profile = HCFProfile.getByPlayer(((Player) sender));
+
+ sender.sendMessage(((profile == null) ? "null" : profile.toDocument().toJson()));
+ }*/
+ }
+
+ @Command(label = "debughcf.resetfactions", permission = "command.debug")
+ public void onResetFactions(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ sender.sendMessage(C.color("&aStarting to reset faction data..."));
+ Faction.getFactions().values().forEach(HCF.getInstance().getBackend()::deleteFaction);
+ Faction.getFactions().clear();
+ Faction.getClaimPositions().clear();
+
+ TaskUtils.runAsync(() -> {
+ HCFProfile.getProfiles().values().forEach(hcfProfile -> {
+ hcfProfile.setFaction(null);
+ hcfProfile.hideMap();
+ });
+
+ sender.sendMessage(C.color("&aFaction data has been reset!"));
+ });
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/EconomyCommand.java b/src/main/java/me/hulipvp/hcf/commands/EconomyCommand.java
new file mode 100644
index 0000000..874cebb
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/EconomyCommand.java
@@ -0,0 +1,123 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class EconomyCommand {
+
+ @Command(label = "economy", aliases = {"eco"}, permission = "command.economy")
+ public void onCommand(CommandData args) {
+ CommandSender sender = args.getSender();
+ this.sendUsage(sender);
+ }
+
+ @Command(label = "economy.add", aliases = {"eco.add", "economy.give", "eco.give"}, permission = "command.economy.add")
+ public void onAddArgument(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ if(args.length() != 3) {
+ this.sendUsage(sender);
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(1));
+ String rawInt = args.getArg(2);
+ if(target == null) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+
+ if(!StringUtils.isInt(rawInt)) {
+ sender.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawInt));
+ return;
+ }
+
+ HCFProfile profile = HCFProfile.getByPlayer(target);
+ int amount = Integer.valueOf(rawInt);
+
+ profile.addToBalance(amount);
+ profile.save();
+ sender.sendMessage(Locale.COMMAND_ECONOMY_GIVEN.toString()
+ .replaceAll("%target%", target.getName())
+ .replaceAll("%amount%", String.valueOf(amount))
+ );
+ }
+ }
+
+ @Command(label = "economy.remove", aliases = {"eco.remove"}, permission = "command.economy.remove")
+ public void onRemoveArgument(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ if(args.length() != 3) {
+ this.sendUsage(sender);
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(1));
+ String rawInt = args.getArg(2);
+ if(target == null) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+
+ if(!StringUtils.isInt(rawInt)) {
+ sender.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawInt));
+ return;
+ }
+
+ HCFProfile profile = HCFProfile.getByPlayer(target);
+ int amount = Integer.valueOf(rawInt);
+
+ profile.removeFromBalance(amount);
+ profile.save();
+ sender.sendMessage(Locale.COMMAND_ECONOMY_TAKEN.toString()
+ .replaceAll("%target%", target.getName())
+ .replaceAll("%amount%", String.valueOf(amount))
+ );
+ }
+ }
+
+ @Command(label = "economy.set", aliases = {"eco.set"}, permission = "command.economy.set")
+ public void onSetArgument(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ if(args.length() != 3) {
+ this.sendUsage(sender);
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(1));
+ String rawInt = args.getArg(2);
+ if(target == null) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+
+ if(!StringUtils.isInt(rawInt)) {
+ sender.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawInt));
+ return;
+ }
+
+ HCFProfile profile = HCFProfile.getByPlayer(target);
+ int amount = Integer.valueOf(rawInt);
+
+ profile.setBalance(amount);
+ profile.save();
+ sender.sendMessage(Locale.COMMAND_ECONOMY_SET.toString()
+ .replaceAll("%player%", target.getName())
+ .replaceAll("%amount%", String.valueOf(amount))
+ );
+ }
+ }
+
+ private void sendUsage(CommandSender sender) {
+ for(String str : HCF.getInstance().getMessagesFile().getEconomyHelp())
+ sender.sendMessage(C.color(str
+ .replaceAll("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replaceAll("%secondary%", ConfigValues.SERVER_SECONDARY)
+ ));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/EotwCommand.java b/src/main/java/me/hulipvp/hcf/commands/EotwCommand.java
new file mode 100644
index 0000000..8b388d8
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/EotwCommand.java
@@ -0,0 +1,80 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.timer.Timer;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimer;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimerType;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class EotwCommand {
+
+ @Command(label = "eotw", permission = "command.eotw")
+ public void onCommand(CommandData args) {
+ args.getSender().sendMessage(Locale.COMMAND_EOTW_USAGE.toString());
+ }
+
+ @Command(label = "eotw.start", permission = "command.eotw.start")
+ public void onStart(CommandData args) {
+ boolean foundTimer = Timer.getTimers().values().stream()
+ .filter(ServerTimer.class::isInstance)
+ .map(ServerTimer.class::cast)
+ .anyMatch(timer -> timer.getType() == ServerTimerType.EOTW);
+
+ if(foundTimer) {
+ args.getSender().sendMessage(Locale.COMMAND_EOTW_ALREADY_STARTING.toString());
+ return;
+ }
+
+ ServerTimer timer = new ServerTimer(ServerTimerType.EOTW);
+ timer.add();
+
+ Bukkit.broadcastMessage(Locale.COMMAND_EOTW_STARTING.toString());
+ }
+
+ @Command(label = "eotw.stop", permission = "command.eotw.stop")
+ public void onStop(CommandData args) {
+ ServerTimer eotwTimer = Timer.getTimers().values().stream()
+ .filter(ServerTimer.class::isInstance)
+ .map(ServerTimer.class::cast)
+ .filter(timer -> timer.getType() == ServerTimerType.EOTW)
+ .findFirst()
+ .orElse(null);
+
+ if(eotwTimer == null) {
+ args.getSender().sendMessage(Locale.COMMAND_EOTW_NOT_RUNNING.toString());
+ return;
+ }
+
+ Timer.getTimers().remove(eotwTimer.getUuid());
+ Bukkit.broadcastMessage(Locale.COMMAND_EOTW_STOPPED.toString());
+ }
+
+ @Command(label = "eotw.commence", permission = "command.eotw.commence")
+ public void onCommence(CommandData args) {
+ if(args.getSender() instanceof Player) {
+ args.getSender().sendMessage(Locale.COMMAND_EOTW_CONSOLE_ONLY.toString());
+ return;
+ }
+
+ Faction.getFactions().values().parallelStream()
+ .filter(PlayerFaction.class::isInstance)
+ .map(PlayerFaction.class::cast)
+ .forEach(faction -> {
+ faction.setDtr(0.0);
+ faction.getRegenTask().cancel();
+ faction.save();
+ });
+
+ Koth eotw = Koth.getKoth("EOTW");
+ if(eotw != null)
+ eotw.start();
+
+ Bukkit.broadcastMessage(Locale.COMMAND_EOTW_COMMENCED.toString());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/FilterCommand.java b/src/main/java/me/hulipvp/hcf/commands/FilterCommand.java
new file mode 100644
index 0000000..3af28ea
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/FilterCommand.java
@@ -0,0 +1,132 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+
+public class FilterCommand {
+
+ // TODO: Make the filter show up through a GUI
+
+ @Command(label = "filter", playerOnly = true)
+ public void onFilter(CommandData args) {
+ Player player = args.getPlayer();
+
+ sendUsage(player);
+ }
+
+ @Command(label = "filter.add", playerOnly = true)
+ public void onFilterAdd(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ if(args.length() != 2) {
+ sendUsage(player);
+ } else {
+ Material material = Material.getMaterial(args.getArg(1).toUpperCase());
+ if(material == null) {
+ player.sendMessage(Locale.COMMAND_FILTER_INVALID_MATERIAL.toString());
+ return;
+ }
+
+ if(profile.getFiltered().contains(material)) {
+ player.sendMessage(Locale.COMMAND_FILTER_ALREADY_ADDED.toString());
+ return;
+ }
+
+ profile.getFiltered().add(material);
+ profile.save();
+ player.sendMessage(Locale.COMMAND_FILTER_ADDED_MATERIAL.toString().replaceAll("%type%", WordUtils.capitalizeFully(material.name().replace("_", " "))));
+ }
+ }
+
+ @Command(label = "filter.remove", playerOnly = true)
+ public void onFilterRemove(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ if(args.length() != 2) {
+ sendUsage(player);
+ } else {
+ Material material = Material.getMaterial(args.getArg(1).toUpperCase());
+ if(material == null) {
+ player.sendMessage(Locale.COMMAND_FILTER_INVALID_MATERIAL.toString());
+ return;
+ }
+
+ if(profile.getFiltered().remove(material)) {
+ profile.save();
+ player.sendMessage(Locale.COMMAND_FILTER_REMOVED_MATERIAL.toString().replaceAll("%type%", WordUtils.capitalizeFully(material.name().replace("_", " "))));
+ } else {
+ player.sendMessage(Locale.COMMAND_FILTER_MATERIAL_NOT_ADDED.toString());
+ }
+ }
+ }
+
+ @Command(label = "filter.toggle", playerOnly = true)
+ public void onFilterToggle(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ profile.setFilterEnabled(!profile.isFilterEnabled());
+ player.sendMessage(Locale.COMMAND_FILTER_TOGGLED.toString().replaceAll("%status%", profile.isFilterEnabled() ? C.color("&aEnabled") : C.color("&cDisabled")));
+ }
+
+ @Command(label = "filter.list", playerOnly = true)
+ public void onFilterList(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ List filtered = profile.getFiltered();
+ player.sendMessage(C.color("&eFiltered Items:" + (filtered.size() == 0 ? " &cNone" : "")));
+ if(filtered.size() > 0) {
+ for(Material material : filtered)
+ player.sendMessage(C.color(" &7- &a" + WordUtils.capitalizeFully(material.name().replaceAll("_", " "))));
+ }
+ }
+
+ @Command(label = "cobble", playerOnly = true)
+ public void onCobble(CommandData args) {
+ toggleMaterial(args.getPlayer(), Material.COBBLESTONE);
+ }
+
+ @Command(label = "stone", playerOnly = true)
+ public void onStone(CommandData args) {
+ toggleMaterial(args.getPlayer(), Material.STONE);
+ }
+
+ private void toggleMaterial(Player player, Material material) {
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ if(profile.getFiltered().remove(material)) {
+ profile.save();
+ player.sendMessage(Locale.COMMAND_FILTER_REMOVED_MATERIAL.toString().replaceAll("%type%", WordUtils.capitalizeFully(material.name().replace("_", " "))));
+ } else {
+ profile.getFiltered().add(material);
+ player.sendMessage(Locale.COMMAND_FILTER_ADDED_MATERIAL.toString().replaceAll("%type%", WordUtils.capitalizeFully(material.name().replace("_", " "))));
+ }
+ profile.setFilterEnabled(true);
+ }
+
+ private void sendUsage(Player player) {
+ for(String str : HCF.getInstance().getMessagesFile().getFilterHelp())
+ player.sendMessage(C.color(str
+ .replaceAll("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replaceAll("%secondary%", ConfigValues.SERVER_SECONDARY)
+ .replaceAll("%servername%", ConfigValues.SERVER_NAME)
+ .replaceAll("%servernamelower%", ConfigValues.SERVER_NAME.toLowerCase())
+ .replaceAll("%website%", ConfigValues.SERVER_WEBSITE)
+ .replaceAll("%teamspeak%", ConfigValues.SERVER_TEAMSPEAK)
+ .replaceAll("%store%", ConfigValues.SERVER_STORE))
+ );
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/FlyCommand.java b/src/main/java/me/hulipvp/hcf/commands/FlyCommand.java
new file mode 100644
index 0000000..5ddc4da
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/FlyCommand.java
@@ -0,0 +1,20 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.entity.Player;
+
+public class FlyCommand {
+
+ @Command(label = "fly", permission = "command.fly", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player player = args.getPlayer();
+
+ player.setAllowFlight(!player.getAllowFlight());
+ player.setFlying(player.getAllowFlight());
+
+ player.sendMessage(Locale.MODMODE_FLY_TOGGLED.toString().replaceAll("%status%", player.getAllowFlight() ? C.color("&aEnabled") : C.color("&cDisabled")));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/GamemodeCommand.java b/src/main/java/me/hulipvp/hcf/commands/GamemodeCommand.java
new file mode 100644
index 0000000..e643267
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/GamemodeCommand.java
@@ -0,0 +1,68 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.GameMode;
+import org.bukkit.entity.Player;
+
+public class GamemodeCommand {
+
+ @Command(label = "gmc", aliases = { "gm.c", "gm.1", "gamemode.c", "gamemode.1" }, permission = "command.gamemode.creative", playerOnly = true)
+ public void onGamemodeCreative(CommandData args) {
+ Player player = args.getPlayer();
+
+ player.setGameMode(GameMode.CREATIVE);
+ player.sendMessage(ChatColor.YELLOW + "Switched gamemode to Creative.");
+ }
+
+ @Command(label = "gms", aliases = { "gm.s", "gm.0", "gamemode.s", "gamemode.0" }, permission = "command.gamemode.survival", playerOnly = true)
+ public void onGamemodeSurvival(CommandData args) {
+ Player player = args.getPlayer();
+
+ player.setGameMode(GameMode.SURVIVAL);
+ player.sendMessage(ChatColor.YELLOW + "Switched gamemode to Survival.");
+ }
+
+ @Command(label = "heal", permission = "command.heal", playerOnly = true)
+ public void onHeal(CommandData args) {
+ Player target;
+ if(args.length() == 0) {
+ target = args.getPlayer();
+ } else {
+ if((target = Bukkit.getPlayer(args.getArg(0))) == null) {
+ args.getPlayer().sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(0)));
+ return;
+ }
+ }
+
+ target.setHealth(target.getMaxHealth());
+ target.setFoodLevel(20);
+
+ target.sendMessage(C.color("&eYou were healed!"));
+ if(!args.getPlayer().getName().equals(target.getName()))
+ args.getPlayer().sendMessage(C.color("&eYou healed player '" + target.getName() + "'."));
+ }
+
+ @Command(label = "feed", permission = "command.feed", playerOnly = true)
+ public void onFeed(CommandData args) {
+ Player target;
+ if(args.length() == 0) {
+ target = args.getPlayer();
+ } else {
+ if((target = Bukkit.getPlayer(args.getArg(0))) == null) {
+ args.getPlayer().sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(0)));
+ return;
+ }
+ }
+
+ target.setFoodLevel(20);
+
+ target.sendMessage(C.color("&eYou were fed!"));
+ if(!args.getPlayer().getName().equals(target.getName()))
+ args.getPlayer().sendMessage(C.color("&eYou fed player '" + target.getName() + "'."));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/HCFCoreCommand.java b/src/main/java/me/hulipvp/hcf/commands/HCFCoreCommand.java
new file mode 100644
index 0000000..d736be5
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/HCFCoreCommand.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.ConfigValues;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class HCFCoreCommand {
+
+ @Command(label = "hcfmeme", permission = "command.hcfcore", playerOnly = true)
+ public void onCommand(CommandData args) {
+ CommandSender sender = args.getSender();
+ sender.sendMessage(ChatColor.AQUA + "Notifyz is a skid");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/commands/HelpCommand.java b/src/main/java/me/hulipvp/hcf/commands/HelpCommand.java
new file mode 100644
index 0000000..504df98
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/HelpCommand.java
@@ -0,0 +1,46 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+
+public class HelpCommand {
+
+ @Command(label = "help", aliases = {"?"})
+ public void onHelp(CommandData args) {
+ for(String str : HCF.getInstance().getMessagesFile().getHelp())
+ args.getSender().sendMessage(C.color(str
+ .replaceAll("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replaceAll("%secondary%", ConfigValues.SERVER_SECONDARY)
+ .replaceAll("%servername%", ConfigValues.SERVER_NAME)
+ .replaceAll("%servernamelower%", ConfigValues.SERVER_NAME.toLowerCase())
+ .replaceAll("%website%", ConfigValues.SERVER_WEBSITE)
+ .replaceAll("%teamspeak%", ConfigValues.SERVER_TEAMSPEAK)
+ .replaceAll("%store%", ConfigValues.SERVER_STORE)
+ .replaceAll("%mapstartdate%", ConfigValues.MAP_START_DATE)
+ .replaceAll("%border%", ConfigValues.LIMITERS_WORLD_BORDER.toString())
+ .replaceAll("%warzone%", ConfigValues.FACTIONS_SIZE_WARZONE.toString())
+ .replaceAll("%map%", ConfigValues.MAP_NUMBER.toString()))
+ );
+ }
+
+ @Command(label = "coords", aliases = {"?"})
+ public void onCoords(CommandData args) {
+ for(String str : HCF.getInstance().getMessagesFile().getCoords())
+ args.getSender().sendMessage(C.color(str
+ .replaceAll("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replaceAll("%secondary%", ConfigValues.SERVER_SECONDARY)
+ .replaceAll("%servername%", ConfigValues.SERVER_NAME)
+ .replaceAll("%servernamelower%", ConfigValues.SERVER_NAME.toLowerCase())
+ .replaceAll("%website%", ConfigValues.SERVER_WEBSITE)
+ .replaceAll("%teamspeak%", ConfigValues.SERVER_TEAMSPEAK)
+ .replaceAll("%store%", ConfigValues.SERVER_STORE)
+ .replaceAll("%mapstartdate%", ConfigValues.MAP_START_DATE)
+ .replaceAll("%border%", ConfigValues.LIMITERS_WORLD_BORDER.toString())
+ .replaceAll("%warzone%", ConfigValues.FACTIONS_SIZE_WARZONE.toString())
+ .replaceAll("%map%", ConfigValues.MAP_NUMBER.toString()))
+ );
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/InstateHCFCommand.java b/src/main/java/me/hulipvp/hcf/commands/InstateHCFCommand.java
new file mode 100644
index 0000000..4e345a7
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/InstateHCFCommand.java
@@ -0,0 +1,176 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.Claim;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.system.EndPortalFaction;
+import me.hulipvp.hcf.game.faction.type.system.RoadFaction;
+import me.hulipvp.hcf.game.faction.type.system.SafezoneFaction;
+import me.hulipvp.hcf.game.faction.type.system.WarzoneFaction;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.TaskUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.CommandSender;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class InstateHCFCommand {
+
+ @Command(label = "instatehcf", permission = "command.instatehcf")
+ public void onCommand(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ sender.sendMessage(C.color("&aRunning this command will create all default factions and configure basic settings."));
+ sender.sendMessage(C.color("&aIf you wish to continue, please run the command:"));
+ sender.sendMessage(C.color("&c/instatehcf confirm"));
+ }
+
+ @Command(label = "instatehcf.confirm", permission = "command.instatehcf")
+ public void onConfirmArgument(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ World defaultWorld = Bukkit.getServer().getWorlds().get(0);
+ World defaultNetherWorld = Bukkit.getServer().getWorlds().get(1);
+
+ TaskUtils.runAsync(() -> {
+ try {
+ sender.sendMessage(C.color("&aStarting to configure default data."));
+
+ if(Faction.getByName("Warzone") == null) {
+ WarzoneFaction warzone = new WarzoneFaction(null);
+// warzone.addClaim(new Claim(
+// new Location(defaultWorld, ConfigValues.FACTIONS_SIZE_WARZONE, 0, ConfigValues.FACTIONS_SIZE_WARZONE),
+// new Location(defaultWorld, -ConfigValues.FACTIONS_SIZE_WARZONE, 256, -ConfigValues.FACTIONS_SIZE_WARZONE)
+// ));
+ HCF.getInstance().getBackend().createFaction(warzone);
+ }
+
+ if(Faction.getByName("End_Portal") == null) {
+ EndPortalFaction endPortal = new EndPortalFaction();
+ HCF.getInstance().getBackend().createFaction(endPortal);
+ }
+
+ Faction spawn, netherSpawn, northRoad, eastRoad, southRoad, westRoad;
+ spawn = Faction.getByName("Spawn");
+ if(spawn == null) {
+ spawn = new SafezoneFaction(null, "Spawn");
+ HCF.getInstance().getBackend().createFaction(spawn);
+ }
+ spawn.removeClaims();
+ spawn.addClaim(new Claim(
+ new Location(defaultWorld, ConfigValues.FACTIONS_SIZE_SPAWN, 0, ConfigValues.FACTIONS_SIZE_SPAWN),
+ new Location(defaultWorld, -ConfigValues.FACTIONS_SIZE_SPAWN, 256, -ConfigValues.FACTIONS_SIZE_SPAWN)
+ ));
+
+ {
+ List facsOne = Faction.getAllByName("Nether_Spawn"), facsTwo = Faction.getAllByName("Nether Spawn");
+ Stream.concat(facsOne.stream(), facsTwo.stream()).forEach(faction -> {
+ faction.removeClaims();
+ HCF.getInstance().getBackend().deleteFaction(faction);
+ Faction.getFactions().remove(faction.getUuid().toString());
+ });
+ }
+
+ netherSpawn = Faction.getByName("Nether_Spawn");
+ if(netherSpawn == null) {
+ netherSpawn = new SafezoneFaction(null, "Nether_Spawn");
+ ((SafezoneFaction) netherSpawn).setColor(ChatColor.RED);
+ HCF.getInstance().getBackend().createFaction(netherSpawn);
+ }
+ netherSpawn.removeClaims();
+ netherSpawn.addClaim(new Claim(
+ new Location(defaultNetherWorld, ConfigValues.FACTIONS_SIZE_NETHER_SPAWN, 0, ConfigValues.FACTIONS_SIZE_NETHER_SPAWN),
+ new Location(defaultNetherWorld, -ConfigValues.FACTIONS_SIZE_NETHER_SPAWN, 256, -ConfigValues.FACTIONS_SIZE_NETHER_SPAWN)
+ ));
+
+ {
+ List norths = Faction.getAllByName("North"), souths = Faction.getAllByName("South"), easts = Faction.getAllByName("East"), wests = Faction.getAllByName("West");
+ Stream.concat(norths.stream(), souths.stream()).forEach(faction -> {
+ faction.removeClaims();
+ HCF.getInstance().getBackend().deleteFaction(faction);
+ Faction.getFactions().remove(faction.getUuid().toString());
+ });
+
+ Stream.concat(easts.stream(), wests.stream()).forEach(faction -> {
+ faction.removeClaims();
+ HCF.getInstance().getBackend().deleteFaction(faction);
+ Faction.getFactions().remove(faction.getUuid().toString());
+ });
+ }
+
+ northRoad = Faction.getByName("North");
+ if(northRoad == null) {
+ northRoad = new RoadFaction(null, "North");
+ HCF.getInstance().getBackend().createFaction(northRoad);
+ }
+ northRoad.removeClaims();
+ northRoad.addClaim(new Claim(
+ new Location(defaultWorld, -ConfigValues.FACTIONS_SIZE_ROAD_WLEFT, 0, -ConfigValues.FACTIONS_SIZE_ROAD_OFFSET),
+ new Location(defaultWorld, ConfigValues.FACTIONS_SIZE_ROAD_WRIGHT, 256, -ConfigValues.FACTIONS_SIZE_ROAD_LENGTH)
+ ));
+ northRoad.addClaim(new Claim(
+ new Location(defaultNetherWorld, -ConfigValues.FACTIONS_SIZE_NETHER_ROAD_WLEFT, 0, -ConfigValues.FACTIONS_SIZE_NETHER_ROAD_OFFSET),
+ new Location(defaultNetherWorld, ConfigValues.FACTIONS_SIZE_NETHER_ROAD_WRIGHT, 256, -ConfigValues.FACTIONS_SIZE_NETHER_ROAD_LENGTH)
+ ));
+
+ eastRoad = Faction.getByName("East");
+ if(eastRoad == null) {
+ eastRoad = new RoadFaction(null, "East");
+ HCF.getInstance().getBackend().createFaction(eastRoad);
+ }
+ eastRoad.removeClaims();
+ eastRoad.addClaim(new Claim(
+ new Location(defaultWorld, ConfigValues.FACTIONS_SIZE_ROAD_OFFSET, 0, -ConfigValues.FACTIONS_SIZE_ROAD_WLEFT),
+ new Location(defaultWorld, ConfigValues.FACTIONS_SIZE_ROAD_LENGTH, 256, ConfigValues.FACTIONS_SIZE_ROAD_WRIGHT)
+ ));
+ eastRoad.addClaim(new Claim(
+ new Location(defaultNetherWorld, ConfigValues.FACTIONS_SIZE_NETHER_ROAD_OFFSET, 0, -ConfigValues.FACTIONS_SIZE_NETHER_ROAD_WLEFT),
+ new Location(defaultNetherWorld, ConfigValues.FACTIONS_SIZE_NETHER_ROAD_LENGTH, 256, ConfigValues.FACTIONS_SIZE_NETHER_ROAD_WRIGHT)
+ ));
+
+ southRoad = Faction.getByName("South");
+ if(southRoad == null) {
+ southRoad = new RoadFaction(null, "South");
+ HCF.getInstance().getBackend().createFaction(southRoad);
+ }
+ southRoad.removeClaims();
+ southRoad.addClaim(new Claim(
+ new Location(defaultWorld, ConfigValues.FACTIONS_SIZE_ROAD_WLEFT, 0, ConfigValues.FACTIONS_SIZE_ROAD_OFFSET),
+ new Location(defaultWorld, -ConfigValues.FACTIONS_SIZE_ROAD_WRIGHT, 256, ConfigValues.FACTIONS_SIZE_ROAD_LENGTH)
+ ));
+ southRoad.addClaim(new Claim(
+ new Location(defaultNetherWorld, ConfigValues.FACTIONS_SIZE_NETHER_ROAD_WLEFT, 0, ConfigValues.FACTIONS_SIZE_NETHER_ROAD_OFFSET),
+ new Location(defaultNetherWorld, -ConfigValues.FACTIONS_SIZE_NETHER_ROAD_WRIGHT, 256, ConfigValues.FACTIONS_SIZE_NETHER_ROAD_LENGTH)
+ ));
+
+ westRoad = Faction.getByName("West");
+ if(Faction.getByName("West") == null) {
+ westRoad = new RoadFaction(null, "West");
+ HCF.getInstance().getBackend().createFaction(westRoad);
+ }
+ westRoad.removeClaims();
+ westRoad.addClaim(new Claim(
+ new Location(defaultWorld, -ConfigValues.FACTIONS_SIZE_ROAD_OFFSET, 0, ConfigValues.FACTIONS_SIZE_ROAD_WLEFT),
+ new Location(defaultWorld, -ConfigValues.FACTIONS_SIZE_ROAD_LENGTH, 256, -ConfigValues.FACTIONS_SIZE_ROAD_WRIGHT)
+ ));
+ westRoad.addClaim(new Claim(
+ new Location(defaultNetherWorld, -ConfigValues.FACTIONS_SIZE_NETHER_ROAD_OFFSET, 0, ConfigValues.FACTIONS_SIZE_NETHER_ROAD_WLEFT),
+ new Location(defaultNetherWorld, -ConfigValues.FACTIONS_SIZE_NETHER_ROAD_LENGTH, 256, -ConfigValues.FACTIONS_SIZE_NETHER_ROAD_WRIGHT)
+ ));
+
+ sender.sendMessage(C.color("&aSuccessfully configured default data."));
+ } catch(Exception ex) {
+ sender.sendMessage(C.color("&aThere was an error configuring default data: " + ex.getMessage() + ". Check console for more info."));
+ ex.printStackTrace();
+ }
+ });
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/ItemCommand.java b/src/main/java/me/hulipvp/hcf/commands/ItemCommand.java
new file mode 100644
index 0000000..dcf6149
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/ItemCommand.java
@@ -0,0 +1,103 @@
+package me.hulipvp.hcf.commands;
+
+import com.google.common.base.Joiner;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.utils.TaskUtils;
+import me.hulipvp.hcf.utils.item.Enchantments;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+public class ItemCommand {
+
+ @Command(label = "enchant", aliases = { "ench" }, permission = "command.enchant", playerOnly = true)
+ public void onEnchant(CommandData args) {
+ Player player = args.getPlayer();
+ if(args.length() < 2) {
+ player.sendMessage(C.color("&cUsage: /" + args.getLabel() + " "));
+ return;
+ }
+
+ ItemStack item = player.getItemInHand();
+ if(item == null || item.getType() == Material.AIR) {
+ player.sendMessage(C.color("&cYou must be holding an item to enchant."));
+ return;
+ }
+
+ Enchantment enchantment = Enchantments.getByName(args.getArg(0));
+ if(enchantment == null) {
+ player.sendMessage(C.color("&cThe enchantment '" + args.getArg(0) + "' does not exist."));
+ return;
+ }
+
+ if(!StringUtils.isInt(args.getArg(1))) {
+ player.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", args.getArg(1)));
+ return;
+ }
+
+ int level = Integer.parseInt(args.getArg(1));
+ if(level <= 0) {
+ player.sendMessage(C.color("&cPlease use a positive number."));
+ return;
+ }
+
+ TaskUtils.runSync(() -> {
+ ItemMeta meta = item.getItemMeta();
+ meta.addEnchant(enchantment, level, true);
+ item.setItemMeta(meta);
+
+ player.setItemInHand(item);
+ player.updateInventory();
+
+ player.sendMessage(C.color("&eAdded " + enchantment.getName() + " level " + level + " to your held item."));
+ });
+ }
+
+ @Command(label = "rename", permission = "command.rename", playerOnly = true)
+ public void onRename(CommandData args) {
+ Player player = args.getPlayer();
+ if(args.length() <= 0) {
+ player.sendMessage(C.color("&cUsage: /" + args.getLabel() + " "));
+ return;
+ }
+
+ ItemStack item = player.getItemInHand();
+ if(item == null || item.getType() == Material.AIR) {
+ player.sendMessage(C.color("&cYou must be holding an item to rename."));
+ return;
+ }
+
+ String name = Joiner.on(' ').join(args.getArgs());
+
+ TaskUtils.runSync(() -> {
+ boolean remove = name.replaceAll(" ", "").equals("remove");
+
+ ItemMeta meta = item.getItemMeta();
+ if(remove)
+ meta.setDisplayName(null);
+ else
+ meta.setDisplayName(C.color(name));
+ item.setItemMeta(meta);
+
+ player.setItemInHand(item);
+ player.updateInventory();
+
+ if(remove)
+ player.sendMessage(C.color("&eRemoved the name of your item."));
+ else
+ player.sendMessage(C.color("&eChanged the name of your item to '" + C.color(name) + "&e'."));
+ });
+ }
+
+ @Command(label = "craft", permission = "command.craft", playerOnly = true)
+ public void onCraft(CommandData args) {
+ Player player = args.getPlayer();
+ player.openWorkbench(null, true);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/LffCommand.java b/src/main/java/me/hulipvp/hcf/commands/LffCommand.java
new file mode 100644
index 0000000..77506dc
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/LffCommand.java
@@ -0,0 +1,52 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.sql.Timestamp;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+public class LffCommand {
+
+ private Map cooldowns;
+
+ public LffCommand() {
+ cooldowns = new HashMap<>();
+ }
+
+ @Command(label = "lff", permission = "command.lff", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player player = args.getPlayer();
+
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+ if(profile.hasFaction()) {
+ player.sendMessage(Locale.COMMAND_FACTION_NOT_ALLOWED.toString());
+ return;
+ }
+
+ long lffCooldown;
+ if(cooldowns.containsKey(player.getUniqueId()) && (lffCooldown = cooldowns.get(player.getUniqueId())) > System.currentTimeMillis()) {
+ player.sendMessage(Locale.COMMAND_LFF_COOLDOWN.toString().replace("%time%", TimeUtils.getTimeTill(new Timestamp(lffCooldown))));
+ return;
+ }
+
+ cooldowns.put(player.getUniqueId(), System.currentTimeMillis() + (TimeUnit.SECONDS.toMillis(ConfigValues.LIMITERS_LFF_COOLDOWN)));
+ HCF.getInstance().getMessagesFile().getLff().forEach(message -> {
+ Bukkit.broadcastMessage(C.color(message
+ .replace("%player%", player.getName())
+ .replaceAll("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replaceAll("%secondary%", ConfigValues.SERVER_SECONDARY)));
+ });
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/LivesCommand.java b/src/main/java/me/hulipvp/hcf/commands/LivesCommand.java
new file mode 100644
index 0000000..4d8b402
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/LivesCommand.java
@@ -0,0 +1,320 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.game.timer.type.server.ServerTimer;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.TimeUtils;
+import me.hulipvp.hcf.utils.player.PlayerUtils;
+import me.hulipvp.hcf.utils.player.UUIDPair;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.sql.Timestamp;
+import java.util.UUID;
+
+public class LivesCommand {
+
+ @Command(label = "lives", playerOnly = true)
+ public void onCommand(CommandData args) {
+ if(ServerTimer.isEotw()) {
+ args.getSender().sendMessage(Locale.COMMAND_LIVES_EOTW.toString());
+ return;
+ }
+
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() != 1) {
+ p.sendMessage(Locale.COMMAND_LIVES.toString()
+ .replaceAll("%lives%", String.valueOf(profile.getLives()))
+ .replaceAll("%store%", ConfigValues.SERVER_STORE)
+ );
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(0));
+ String targetName;
+ UUID targetUuid;
+
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(0));
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ HCFProfile targetProfile = HCFProfile.getByUuid(targetUuid);
+ p.sendMessage(Locale.COMMAND_LIVES_OTHER.toString()
+ .replaceAll("%name%", targetName)
+ .replaceAll("%lives%", String.valueOf(targetProfile.getLives()))
+ );
+ }
+ }
+
+ @Command(label = "lives.set", permission = "command.lives")
+ public void onLivesSet(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(ServerTimer.isEotw()) {
+ sender.sendMessage(Locale.COMMAND_LIVES_EOTW.toString());
+ return;
+ }
+
+ if(args.length() < 3) {
+ this.sendUsage(sender);
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(1));
+ String targetName;
+ UUID targetUuid;
+ HCFProfile profile;
+
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(1));
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ profile = HCFProfile.getByUuid(targetUuid);
+ String rawInt = args.getArg(2);
+ if(!StringUtils.isInt(rawInt)) {
+ sender.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawInt));
+ return;
+ }
+
+ int amount = Integer.parseInt(rawInt);
+ profile.setLives(amount);
+ profile.save();
+ sender.sendMessage(Locale.COMMAND_LIVES_SET.toString()
+ .replaceAll("%name%", targetName)
+ .replaceAll("%amount%", String.valueOf(amount))
+ );
+ }
+ }
+
+ @Command(label = "lives.give", permission = "command.lives", playerOnly = true)
+ public void onLivesGive(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(ServerTimer.isEotw()) {
+ sender.sendMessage(Locale.COMMAND_LIVES_EOTW.toString());
+ return;
+ }
+
+ if(args.length() < 3) {
+ this.sendUsage(sender);
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(1));
+ String targetName;
+ UUID targetUuid;
+ HCFProfile targetProfile;
+
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(1));
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ targetProfile = HCFProfile.getByUuid(targetUuid);
+ String rawInt = args.getArg(2);
+ if(!StringUtils.isInt(rawInt)) {
+ sender.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawInt));
+ return;
+ }
+
+ int amount = Integer.parseInt(rawInt);
+ HCFProfile profile = HCFProfile.getByPlayer(args.getPlayer());
+ if(amount < 0 || profile.getLives() < amount) {
+ sender.sendMessage(Locale.COMMAND_LIVES_NOT_ENOUGH.toString());
+ return;
+ }
+
+ profile.setLives(profile.getLives() - amount);
+ profile.save();
+
+ targetProfile.setLives(targetProfile.getLives() + amount);
+ targetProfile.save();
+ sender.sendMessage(Locale.COMMAND_LIVES_GIVEN.toString()
+ .replaceAll("%name%", targetName)
+ .replaceAll("%amount%", String.valueOf(amount))
+ );
+
+ if(target != null && target.isOnline())
+ target.sendMessage(Locale.COMMAND_LIVES_RECEIVED.toString()
+ .replaceAll("%name%", targetName)
+ .replaceAll("%amount%", String.valueOf(amount))
+ );
+ }
+ }
+
+ @Command(label = "lives.add", permission = "command.lives")
+ public void onLivesAdd(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(ServerTimer.isEotw()) {
+ sender.sendMessage(Locale.COMMAND_LIVES_EOTW.toString());
+ return;
+ }
+
+ if(args.length() < 3) {
+ this.sendUsage(sender);
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(1));
+ String targetName;
+ UUID targetUuid;
+ HCFProfile profile;
+
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(1));
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ profile = HCFProfile.getByUuid(targetUuid);
+ String rawInt = args.getArg(2);
+ if(!StringUtils.isInt(rawInt)) {
+ sender.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawInt));
+ return;
+ }
+
+ int amount = Integer.parseInt(rawInt);
+ profile.setLives(profile.getLives() + amount);
+ profile.save();
+ sender.sendMessage(Locale.COMMAND_LIVES_GIVEN.toString()
+ .replaceAll("%name%", targetName)
+ .replaceAll("%amount%", String.valueOf(amount))
+ );
+ }
+ }
+
+ @Command(label = "lives.take", permission = "command.lives")
+ public void onLivesTake(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(ServerTimer.isEotw()) {
+ sender.sendMessage(Locale.COMMAND_LIVES_EOTW.toString());
+ return;
+ }
+
+ if(args.length() < 3) {
+ this.sendUsage(sender);
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(1));
+ String targetName;
+ UUID targetUuid;
+ HCFProfile profile;
+
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(1));
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ profile = HCFProfile.getByUuid(targetUuid);
+ String rawInt = args.getArg(2);
+ if(!StringUtils.isInt(rawInt)) {
+ sender.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawInt));
+ return;
+ }
+
+ int amount = Integer.parseInt(rawInt);
+ profile.setLives(profile.getLives() - amount);
+ profile.save();
+ sender.sendMessage(Locale.COMMAND_LIVES_TAKEN.toString()
+ .replaceAll("%name%", targetName)
+ .replaceAll("%amount%", String.valueOf(amount))
+ );
+ }
+ }
+
+ @Command(label = "lives.checkdeathban", permission = "command.lives")
+ public void onCheckDeathban(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(ServerTimer.isEotw()) {
+ sender.sendMessage(Locale.COMMAND_LIVES_EOTW.toString());
+ return;
+ }
+
+ if(args.length() < 2) {
+ this.sendUsage(sender);
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(1));
+ String targetName;
+ UUID targetUuid;
+ HCFProfile profile;
+
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(1));
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ profile = HCFProfile.getByUuid(targetUuid);
+ if(profile.getBannedTill() == 0 || (System.currentTimeMillis() > profile.getBannedTill())) {
+ sender.sendMessage(Locale.COMMAND_REVIVE_NO_DEATHBAN.toString().replaceAll("%player%", targetName));
+ return;
+ }
+
+ String remainingTime = TimeUtils.getTimeTill(new Timestamp(profile.getBannedTill()));
+ if(remainingTime != null)
+ sender.sendMessage(Locale.COMMAND_LIVES_CHECK.toString().replace("%name%", targetName).replace("%time%", remainingTime));
+ else
+ sender.sendMessage(Locale.COMMAND_REVIVE_NO_DEATHBAN.toString().replaceAll("%player%", targetName));
+ }
+ }
+
+ private void sendUsage(CommandSender sender) {
+ for(String str : HCF.getInstance().getMessagesFile().getLivesHelp())
+ sender.sendMessage(C.color(str
+ .replaceAll("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replaceAll("%secondary%", ConfigValues.SERVER_SECONDARY))
+ );
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/LogoutCommand.java b/src/main/java/me/hulipvp/hcf/commands/LogoutCommand.java
new file mode 100644
index 0000000..7888047
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/LogoutCommand.java
@@ -0,0 +1,27 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimer;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimerType;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class LogoutCommand {
+
+ @Command(label = "logout", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(!profile.hasTimer(PlayerTimerType.LOGOUT)) {
+ PlayerTimer logout = new PlayerTimer(p, PlayerTimerType.LOGOUT);
+ logout.add();
+
+ p.sendMessage(Locale.TIMER_LOGOUT.toString());
+ } else {
+ p.sendMessage(Locale.TIMER_LOGOUT_RUNNING.toString());
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/MapkitCommand.java b/src/main/java/me/hulipvp/hcf/commands/MapkitCommand.java
new file mode 100644
index 0000000..d63d9f5
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/MapkitCommand.java
@@ -0,0 +1,281 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.game.kits.MapKit;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.player.data.PlayerInv;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.item.Enchantments;
+import me.hulipvp.hcf.utils.item.ItemBuilder;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.potion.PotionType;
+
+import java.util.concurrent.TimeUnit;
+
+public class MapkitCommand {
+
+ private Inventory mapkitInv;
+
+ public MapkitCommand() {
+ buildMapKitInventory();
+ }
+
+ @Command(label = "mapkit", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ p.openInventory(mapkitInv);
+ }
+
+ @Command(label = "mapkit.create", permission = "mapkit.admin", playerOnly = true)
+ public void onMapkitCreate(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() < 2) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_USAGE.toString());
+ } else {
+ String kit = args.getArg(1);
+ if(HCF.getInstance().getKitsFile().isValidKit(kit)) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_ALREADY_EXISTS.toString());
+ return;
+ }
+
+ MapKit mapKit = new MapKit(kit);
+ mapKit.setPlayerInv(PlayerInv.fromPlayer(p.getInventory()));
+ mapKit.setEnabled(true);
+ mapKit.setColor(ChatColor.GREEN);
+
+ HCF.getInstance().getKitsFile().getKits().put(kit, mapKit);
+ HCF.getInstance().getKitsFile().saveKit(mapKit);
+ p.sendMessage(Locale.COMMAND_MAPKIT_CREATED.toString().replaceAll("%type%", kit));
+ }
+ }
+
+ @Command(label = "mapkit.delete", permission = "mapkit.admin", playerOnly = true)
+ public void onMapkitDelete(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() < 2) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_USAGE.toString());
+ } else {
+ String kit = args.getArg(1);
+ if(!HCF.getInstance().getKitsFile().isValidKit(kit)) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_ALREADY_EXISTS.toString());
+ return;
+ }
+
+ HCF.getInstance().getKitsFile().getKits().remove(kit);
+ HCF.getInstance().getKitsFile().saveKits();
+ p.sendMessage(Locale.COMMAND_MAPKIT_DELETED.toString().replaceAll("%type%", kit));
+ }
+ }
+
+ @Command(label = "mapkit.toggle", permission = "mapkit.admin", playerOnly = true)
+ public void onMapkitToggle(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() < 2) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_USAGE.toString());
+ } else {
+ String kit = args.getArg(1);
+ if(!HCF.getInstance().getKitsFile().isValidKit(kit)) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_INVALID_KIT.toString());
+ return;
+ }
+
+ HCF.getInstance().getKitsFile().setEnabled(kit, !HCF.getInstance().getKitsFile().isEnabled(kit));
+ p.sendMessage(Locale.COMMAND_MAPKIT_TOGGLED.toString().replaceAll("%type%", kit)
+ .replaceAll("%status%", HCF.getInstance().getKitsFile().isEnabled(kit) ? C.color("&aEnabled") : C.color("&cDisabled")));
+ }
+ }
+
+ @Command(label = "mapkit.update", permission = "mapkit.admin", playerOnly = true)
+ public void onMapkitSetinv(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() < 2) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_USAGE.toString());
+ } else {
+ String kit = args.getArg(1);
+ if(!HCF.getInstance().getKitsFile().isValidKit(kit)) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_INVALID_KIT.toString());
+ return;
+ }
+
+ HCF.getInstance().getKitsFile().setMapkitInv(kit, PlayerInv.fromPlayer(p.getInventory()));
+ p.sendMessage(Locale.COMMAND_MAPKIT_UPDATED.toString().replaceAll("%type%", kit));
+ }
+ }
+
+ @Command(label = "mapkit.load", permission = "mapkit.admin", playerOnly = true)
+ public void onMapkitLoadInv(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() < 2) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_USAGE.toString());
+ } else {
+ String kit = args.getArg(1);
+ if(!HCF.getInstance().getKitsFile().isValidKit(kit)) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_INVALID_KIT.toString());
+ return;
+ }
+
+ HCF.getInstance().getKitsFile().getMapkitInv(kit).load(p);
+ p.sendMessage(Locale.COMMAND_MAPKIT_LOADED.toString().replaceAll("%type%", kit));
+ }
+ }
+
+ @Command(label = "mapkit.setcolor", permission = "mapkit.admin", playerOnly = true)
+ public void onMapkitSetcolor(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() < 3) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_USAGE.toString());
+ } else {
+ String kit = args.getArg(1);
+ if(!HCF.getInstance().getKitsFile().isValidKit(kit)) {
+ p.sendMessage(Locale.COMMAND_MAPKIT_INVALID_KIT.toString());
+ return;
+ }
+
+ ChatColor color;
+ try {
+ color = ChatColor.valueOf(args.getArg(2));
+ } catch(Exception ex) {
+ p.sendMessage(C.color("&cThat color is not a valid color."));
+ return;
+ }
+
+ HCF.getInstance().getKitsFile().setColor(kit, color);
+ p.sendMessage(Locale.COMMAND_MAPKIT_SET_COLOR.toString().replaceAll("%type%", kit)
+ .replaceAll("%color%", WordUtils.capitalizeFully(color.name())));
+ }
+ }
+
+ private void buildMapKitInventory() {
+ mapkitInv = Bukkit.createInventory(null, 54, C.color(ConfigValues.SERVER_PRIMARY + "Mapkit"));
+
+ ItemStack outline = new ItemBuilder(new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) 7))
+ .name("")
+ .get();
+
+ Integer protLimit = ConfigValues.LIMITERS_ENCHANTS.get(Enchantment.PROTECTION_ENVIRONMENTAL);
+ Integer unbreakLimit = ConfigValues.LIMITERS_ENCHANTS.get(Enchantment.DURABILITY);
+ Integer fallLimit = ConfigValues.LIMITERS_ENCHANTS.get(Enchantment.PROTECTION_FALL);
+ Integer sharpLimit = ConfigValues.LIMITERS_ENCHANTS.get(Enchantment.DAMAGE_ALL);
+ Integer fireLimit = ConfigValues.LIMITERS_ENCHANTS.get(Enchantment.FIRE_ASPECT);
+ Integer powerLimit = ConfigValues.LIMITERS_ENCHANTS.get(Enchantment.ARROW_DAMAGE);
+ Integer punchLimit = ConfigValues.LIMITERS_ENCHANTS.get(Enchantment.ARROW_KNOCKBACK);
+ Integer flameLimit = ConfigValues.LIMITERS_ENCHANTS.get(Enchantment.ARROW_FIRE);
+ Integer infitityLimit = ConfigValues.LIMITERS_ENCHANTS.get(Enchantment.ARROW_INFINITE);
+
+ PotionType poisonType = PotionType.getByEffect(PotionEffectType.getByName("POISON"));
+ String[] poisonInfo = ((ConfigValues.LIMITERS_POTIONS.get(poisonType) == null) ? new String[]{ "1", "0:33" } : ConfigValues.LIMITERS_POTIONS.get(poisonType).split(";"));
+
+ PotionType slownessType = PotionType.getByEffect(PotionEffectType.getByName("SLOWNESS"));
+ String[] slownessInfo = ((ConfigValues.LIMITERS_POTIONS.get(slownessType) == null) ? new String[]{ "1", "1:07" } : ConfigValues.LIMITERS_POTIONS.get(slownessType).split(";"));
+
+ ItemStack helmet = new ItemBuilder(Material.DIAMOND_HELMET)
+ .name("&bDiamond Helmet")
+ .lore(
+ "&7Protection " + ((protLimit == null) ? 4 : protLimit),
+ "&7Unbreaking " + ((unbreakLimit == null) ? 3 : unbreakLimit)
+ )
+ .get();
+
+ ItemStack chestplate = new ItemBuilder(Material.DIAMOND_CHESTPLATE)
+ .name("&bDiamond Chestplate")
+ .lore(
+ "&7Protection " + ((protLimit == null) ? 4 : protLimit),
+ "&7Unbreaking " + ((unbreakLimit == null) ? 3 : unbreakLimit)
+ )
+ .get();
+
+ ItemStack leggings = new ItemBuilder(Material.DIAMOND_LEGGINGS)
+ .name("&bDiamond Leggings")
+ .lore(
+ "&7Protection " + ((protLimit == null) ? 4 : protLimit),
+ "&7Unbreaking " + ((unbreakLimit == null) ? 3 : unbreakLimit)
+ )
+ .get();
+
+ ItemStack boots = new ItemBuilder(Material.DIAMOND_BOOTS)
+ .name("&bDiamond Boots")
+ .lore(
+ "&7Protection " + ((protLimit == null) ? 4 : protLimit),
+ "&7Unbreaking " + ((unbreakLimit == null) ? 3 : unbreakLimit),
+ "&7Feather Falling " + ((fallLimit == null) ? 4 : fallLimit)
+ )
+ .get();
+
+ ItemStack sword = new ItemBuilder(Material.DIAMOND_SWORD)
+ .name("&bDiamond Sword")
+ .lore(
+ "&7Sharpness " + ((sharpLimit == null) ? 5 : sharpLimit),
+ "&7Fire Aspect " + ((fireLimit == null) ? 2 : fireLimit),
+ "&7Unbreaking " + ((unbreakLimit == null) ? 3 : unbreakLimit)
+ )
+ .get();
+
+ ItemStack bow = new ItemBuilder(Material.BOW)
+ .name("&bBow")
+ .lore(
+ "&7Power " + ((powerLimit == null) ? 5 : powerLimit),
+ "&7Punch " + ((punchLimit == null) ? 2 : punchLimit),
+ "&7Flame " + ((flameLimit == null) ? 1 : flameLimit),
+ "&7Infinity " + ((infitityLimit == null) ? 1 : infitityLimit),
+ "&7Unbreaking " + ((unbreakLimit == null) ? 3 : unbreakLimit)
+ )
+ .get();
+
+ ItemStack poison = new ItemBuilder(Material.POTION)
+ .name("&bPoison")
+ .durability(16388)
+ .lore(
+ "",
+ "&7Max Level: " + poisonInfo[0],
+ "&7Max Duration: " + (poisonInfo[1].contains(":") ? poisonInfo[1] : TimeUtils.getFormatted(TimeUnit.SECONDS.toMillis(Long.valueOf(poisonInfo[1]))))
+ )
+ .get();
+
+ ItemStack slowness = new ItemBuilder(Material.POTION)
+ .name("&bSlowness")
+ .durability(16394)
+ .lore(
+ "",
+ "&7Max Level: " + slownessInfo[0],
+ "&7Max Duration: " + (slownessInfo[1].contains(":") ? slownessInfo[1] : TimeUtils.getFormatted(TimeUnit.SECONDS.toMillis(Long.valueOf(slownessInfo[1]))))
+ )
+ .get();
+
+ mapkitInv.setItem(13, helmet);
+ mapkitInv.setItem(22, chestplate);
+ mapkitInv.setItem(31, leggings);
+ mapkitInv.setItem(40, boots);
+
+ mapkitInv.setItem(21, sword);
+ mapkitInv.setItem(23, bow);
+
+ mapkitInv.setItem(30, poison);
+ mapkitInv.setItem(32, slowness);
+
+ for(int i = 0; i < 54; i++) {
+ if(mapkitInv.getItem(i) != null)
+ continue;
+
+ mapkitInv.setItem(i, outline);
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/MessageCommand.java b/src/main/java/me/hulipvp/hcf/commands/MessageCommand.java
new file mode 100644
index 0000000..fc8248c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/MessageCommand.java
@@ -0,0 +1,154 @@
+package me.hulipvp.hcf.commands;
+
+import com.google.common.base.Joiner;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Sound;
+import org.bukkit.entity.Player;
+
+public class MessageCommand {
+
+ @Command(label = "m", aliases = { "msg", "message", "t", "tell", "w", "whisper" }, playerOnly = true)
+ public void onMessage(CommandData args) {
+ Player player = args.getPlayer();
+ if(args.length() < 2) {
+ player.sendMessage(Locale.COMMAND_MESSAGE_USAGE.toString().replace("%label%", args.getLabel()));
+ return;
+ }
+
+ if(args.getArg(0).equalsIgnoreCase(player.getName())) {
+ player.sendMessage(Locale.COMMAND_MESSAGE_SELF.toString());
+ return;
+ }
+
+ Player target = Bukkit.getPlayer(args.getArg(0));
+ if(target == null) {
+ player.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(0)));
+ return;
+ }
+
+ HCFProfile messagee = HCFProfile.getByPlayer(player);
+ HCFProfile messager = HCFProfile.getByPlayer(target);
+ if(!player.isOp() && messager.getModMode() != null && messager.getModMode().isVanished()) {
+ player.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(0)));
+ return;
+ }
+
+ if(messager.getIgnored().contains(messagee.getUuid().toString()) || messagee.getIgnored().contains(messager.getUuid().toString())) {
+ player.sendMessage(Locale.COMMAND_MESSAGE_CANNOT.toString());
+ return;
+ }
+
+ if(messagee.isMessagingEnabled()) {
+ if(messager.isMessagingEnabled()) {
+ messagee.setLastMessaged(target);
+ messager.setLastMessaged(player);
+
+ String message = Joiner.on(' ').join(args.getArgs()).replaceFirst(args.getArg(0), "").replaceFirst(" ", "");
+
+ player.sendMessage(Locale.COMMAND_MESSAGE_FORMAT_TO.toString().replace("%recipient%", messager.getChatPrefix()).replace("%message%", message));
+ target.sendMessage(Locale.COMMAND_MESSAGE_FORMAT_FROM.toString().replace("%sender%", messagee.getChatPrefix()).replace("%message%", message));
+
+ if(messager.isMessagingSounds())
+ target.playSound(target.getLocation(), Sound.SUCCESSFUL_HIT, 1, 0);
+ } else {
+ player.sendMessage(Locale.COMMAND_MESSAGE_DISABLED.toString());
+ }
+ } else {
+ player.sendMessage(Locale.COMMAND_MESSAGE_PLAYER_DISABLED.toString());
+ }
+ }
+
+ @Command(label = "r", aliases = { "reply", "respond", "answer" }, playerOnly = true)
+ public void onReply(CommandData args) {
+ Player player = args.getPlayer();
+ if(args.length() < 1) {
+ player.sendMessage(Locale.COMMAND_REPLY_USAGE.toString().replace("%label%", args.getLabel()));
+ return;
+ }
+
+ HCFProfile replier = HCFProfile.getByPlayer(player);
+ Player target = replier.getLastMessaged();
+ if(target == null || !target.isOnline()) {
+ player.sendMessage(target == null ? Locale.COMMAND_REPLY_NO_PLAYER.toString() : Locale.COMMAND_REPLY_PLAYER_OFFLINE.toString());
+ return;
+ }
+
+ HCFProfile lastMessaged = HCFProfile.getByPlayer(target);
+ if(!player.isOp() && lastMessaged.getModMode() != null && lastMessaged.getModMode().isVanished()) {
+ player.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(0)));
+ return;
+ }
+
+ if(replier.getIgnored().contains(lastMessaged.getUuid().toString()) || lastMessaged.getIgnored().contains(replier.getUuid().toString())) {
+ player.sendMessage(Locale.COMMAND_MESSAGE_CANNOT.toString());
+ return;
+ }
+
+ lastMessaged.setLastMessaged(player);
+ String message = Joiner.on(' ').join(args.getArgs());
+
+ player.sendMessage(Locale.COMMAND_MESSAGE_FORMAT_TO.toString().replace("%recipient%", lastMessaged.getChatPrefix()).replace("%message%", message));
+ target.sendMessage(Locale.COMMAND_MESSAGE_FORMAT_FROM.toString().replace("%sender%", replier.getChatPrefix()).replace("%message%", message));
+
+ if(lastMessaged.isMessagingSounds())
+ target.playSound(target.getLocation(), Sound.SUCCESSFUL_HIT, 1, 0);
+ }
+
+ @Command(label = "ignore", playerOnly = true)
+ public void onIgnore(CommandData args) {
+ Player player = args.getPlayer();
+ if(args.length() != 1) {
+ player.sendMessage(Locale.COMMAND_IGNORE_USAGE.toString());
+ return;
+ }
+
+ if(args.getArg(0).equalsIgnoreCase(player.getName())) {
+ player.sendMessage(ChatColor.RED + "You cannot ignore yourself.");
+ return;
+ }
+
+ Player target = Bukkit.getPlayer(args.getArg(0));
+ if(target == null) {
+ player.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(0)));
+ return;
+ }
+ if(target.hasPermission("hcf.staff")) {
+ player.sendMessage(Locale.COMMAND_IGNORE_CANNOT.toString());
+ return;
+ }
+
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+ if(profile.getIgnored().contains(target.getUniqueId().toString()))
+ profile.getIgnored().remove(target.getUniqueId().toString());
+ else
+ profile.getIgnored().add(target.getUniqueId().toString());
+ profile.save();
+
+ player.sendMessage(Locale.COMMAND_IGNORE_PLAYER.toString().replace("%status%", C.color(profile.getIgnored().contains(target.getUniqueId().toString()) ? "&anow" : "&cno longer")).replace("%player%", target.getName()));
+ }
+
+ @Command(label = "tpm", aliases = { "togglepm", "togglemessages" }, playerOnly = true)
+ public void onToggleMessages(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ profile.setMessagingEnabled(!profile.isMessagingEnabled());
+ player.sendMessage(Locale.COMMAND_MESSAGE_TOGGLED.toString().replace("%status%", C.color(profile.isMessagingEnabled() ? "&aenabled" : "&cdisabled")));
+ }
+
+ @Command(label = "sounds", aliases = { "togglesounds", "togglemessagesounds" }, playerOnly = true)
+ public void onToggleSounds(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ profile.setMessagingSounds(!profile.isMessagingSounds());
+ player.sendMessage(Locale.COMMAND_MESSAGE_TOGGLED_SOUNDS.toString().replace("%status%", C.color(profile.isMessagingSounds() ? "&aenabled" : "&cdisabled")));
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/ModCommand.java b/src/main/java/me/hulipvp/hcf/commands/ModCommand.java
new file mode 100644
index 0000000..7ba1eed
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/ModCommand.java
@@ -0,0 +1,251 @@
+package me.hulipvp.hcf.commands;
+
+import com.google.common.base.Joiner;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.player.data.mod.ModMode;
+import me.hulipvp.hcf.listeners.player.PlayerListener;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.World;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.metadata.FixedMetadataValue;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+public class ModCommand {
+
+ public static List paniced;
+
+ public ModCommand() {
+ paniced = new ArrayList<>();
+ }
+
+ @Command(label = "mod", aliases = { "h", "modmode", "staff", "staffmode" }, permission = "command.mod", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getModMode() == null) {
+ profile.setModMode(new ModMode(p));
+ profile.getModMode().enable();
+ p.sendMessage(Locale.MODMODE_ENABLED.toString());
+ } else {
+ profile.getModMode().disable();
+ profile.setModMode(null);
+ p.sendMessage(Locale.MODMODE_DISABLED.toString());
+ }
+ }
+
+ @Command(label = "invsee", permission = "command.invsee", playerOnly = true)
+ public void onInvSee(CommandData args) {
+ Player player = args.getPlayer();
+ if(args.length() < 1) {
+ player.sendMessage(C.color("&cUsage: /invsee "));
+ return;
+ }
+
+ Player target = Bukkit.getPlayerExact(args.getArg(0));
+ if(target == null || !target.isOnline()) {
+ player.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ return;
+ }
+
+ player.openInventory(target.getInventory());
+ player.sendMessage(Locale.MODMODE_INVSEE.toString().replaceAll("%player%", target.getName()));
+ }
+
+ @Command(label = "panic", aliases = { "unpanic" }, permission = "command.panic", playerOnly = true)
+ public void onPanic(CommandData args) {
+ Player player = args.getPlayer();
+ if(!paniced.contains(player.getUniqueId())) {
+ paniced.add(player.getUniqueId());
+
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "freeze " + player.getName());
+
+ player.sendMessage(Locale.PANIC_INITIATED.toString());
+ String broadcast = Locale.PANIC_BROADCAST.toString().replaceAll("%player%", player.getName());
+ Bukkit.getOnlinePlayers().stream()
+ .filter(staff -> staff.hasPermission("hcf.staff"))
+ .forEach(staff -> staff.sendMessage(broadcast));
+ } else {
+ paniced.remove(player.getUniqueId());
+
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "unfreeze " + player.getName());
+
+ player.sendMessage(Locale.PANIC_FINE.toString());
+ }
+ }
+
+ @Command(label = "freeze", aliases = { "ss", "unfreeze" }, permission = "command.freeze")
+ public void onFreeze(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(args.length() < 1) {
+ sender.sendMessage(C.color("&cUsage: /" + args.getLabel() + " "));
+ return;
+ }
+
+ Player target = Bukkit.getPlayer(args.getArg(0));
+ if(target == null) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ return;
+ }
+
+ if(target.hasMetadata("frozen")) {
+ paniced.remove(target.getUniqueId());
+ target.removeMetadata("frozen", HCF.getInstance());
+
+ target.sendMessage(Locale.FREEZE_UNFROZEN.toString());
+ sender.sendMessage(Locale.FREEZE_UNFROZE_PLAYER.toString().replaceAll("%player%", target.getName()));
+ return;
+ }
+
+ target.setMetadata("frozen", new FixedMetadataValue(HCF.getInstance(), true));
+
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if(!target.isOnline() || !target.hasMetadata("frozen")) {
+ cancel();
+ return;
+ }
+
+ if(paniced.contains(target.getUniqueId())) {
+ String broadcast = Locale.PANIC_BROADCAST.toString().replaceAll("%player%", target.getName());
+ Bukkit.getOnlinePlayers().stream()
+ .filter(staff -> staff.hasPermission("hcf.staff"))
+ .forEach(staff -> staff.sendMessage(broadcast));
+
+ target.sendMessage(C.color("&fโโโโ&cโ&fโโโโ"));
+ target.sendMessage(C.color("&fโโโ&cโ&6โ&cโ&fโโโ &c&lYou are in a panic!"));
+ target.sendMessage(C.color("&fโโ&cโ&6โ&0โ&6โ&cโ&fโโ"));
+ target.sendMessage(C.color("&fโโ&cโ&6โ&0โ&6โ&cโ&fโโ &ePlease wait for a staff"));
+ target.sendMessage(C.color("&fโ&cโ&6โโ&0โ&6โโ&cโ&fโ &amember to contact you!"));
+ target.sendMessage(C.color("&fโ&cโ&6โโโโโ&cโ&fโ"));
+ target.sendMessage(C.color("&cโ&6โโโ&0โ&6โโโ&cโ &c&n" + ConfigValues.SERVER_TEAMSPEAK));
+ target.sendMessage(C.color("&cโโโโโโโโโ"));
+ } else {
+ target.sendMessage(C.color("&fโโโโ&cโ&fโโโโ"));
+ target.sendMessage(C.color("&fโโโ&cโ&6โ&cโ&fโโโ &c&lYou have been frozen!"));
+ target.sendMessage(C.color("&fโโ&cโ&6โ&0โ&6โ&cโ&fโโ"));
+ target.sendMessage(C.color("&fโโ&cโ&6โ&0โ&6โ&cโ&fโโ &eLogging out will be a ban!"));
+ target.sendMessage(C.color("&fโ&cโ&6โโ&0โ&6โโ&cโ&fโ &aPlease join our teamspeak"));
+ target.sendMessage(C.color("&fโ&cโ&6โโโโโ&cโ&fโ"));
+ target.sendMessage(C.color("&cโ&6โโโ&0โ&6โโโ&cโ &c&n" + ConfigValues.SERVER_TEAMSPEAK));
+ target.sendMessage(C.color("&cโโโโโโโโโ"));
+
+ if(ConfigValues.FREEZE_GUI_ENABLED)
+ target.openInventory(PlayerListener.frozenInventory);
+ }
+ }
+ }.runTaskTimerAsynchronously(HCF.getInstance(), 0L, 20L * ConfigValues.FREEZE_MESSAGE_REPEAT);
+
+ sender.sendMessage(Locale.FREEZE_FROZE_PLAYER.toString().replaceAll("%player%", target.getName()));
+ }
+
+
+ @Command(label = "world", permission = "command.world", playerOnly = true)
+ public void onWorld(CommandData args) {
+ Player player = args.getPlayer();
+ if(args.length() < 1) {
+ player.sendMessage(C.color("&cUsage: /world "));
+ return;
+ }
+
+ World world;
+ try {
+ if(StringUtils.isInt(args.getArg(0)))
+ world = Bukkit.getWorlds().get(Integer.parseInt(args.getArg(0)));
+ else
+ world = Bukkit.getWorld(args.getArg(0));
+ } catch(Exception ex) {
+ world = null;
+ }
+
+ if(world == null) {
+ player.sendMessage(C.color("&cThe world with the name of id of '" + args.getArg(0) + "' does not exist."));
+ return;
+ }
+
+ player.teleport(world.getSpawnLocation());
+ player.sendMessage(C.color("&eTeleporting to world " + world.getName() + "..."));
+ }
+
+ @Command(label = "report", playerOnly = true)
+ public void onReport(CommandData args) {
+ Player player = (Player) args.getSender();
+ if(args.length() < 2) {
+ player.sendMessage(Locale.COMMAND_REPORT_USAGE.toString());
+ return;
+ }
+
+ Player target = Bukkit.getPlayer(args.getArg(0));
+ if(target == null) {
+ player.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ return;
+ }
+
+ if(target.getUniqueId().equals(player.getUniqueId())) {
+ player.sendMessage(Locale.COMMAND_REPORT_SELF.toString());
+ return;
+ }
+
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+ if(System.currentTimeMillis() - profile.getLastReportTime() < 8000) {
+ player.sendMessage(Locale.COMMAND_REPORT_COOLDOWN.toString());
+ return;
+ }
+
+ String reason = Joiner.on(' ').join(args.getArgs()).replaceFirst(args.getArg(0), "").replaceFirst(" ", "");
+ String message = Locale.COMMAND_REPORT_BROADCAST.toString().replace("%reported%", target.getName()).replace("%reporter%", player.getName()).replace("%reason%", reason);
+ Bukkit.getOnlinePlayers().stream()
+ .filter(staff -> staff.hasPermission("hcf.staff"))
+ .forEach(staff -> staff.sendMessage(message));
+
+ player.sendMessage(Locale.COMMAND_REPORT_SUCCESS.toString());
+ profile.setLastReportTime(System.currentTimeMillis());
+ }
+
+ @Command(label = "request", aliases = { "helpop" }, playerOnly = true)
+ public void onRequest(CommandData args) {
+ Player player = (Player) args.getSender();
+ if(args.length() == 0) {
+ player.sendMessage(Locale.COMMAND_REQUEST_USAGE.toString());
+ return;
+ }
+
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+ if(System.currentTimeMillis() - profile.getLastRequestTime() < 8000) {
+ player.sendMessage(Locale.COMAMND_REQUEST_COOLDOWN.toString());
+ return;
+ }
+
+ String message = Locale.COMMAND_REQUEST_BROADCAST.toString().replace("%sender%", player.getName()).replace("%message%", Joiner.on(' ').join(args.getArgs()));
+ Bukkit.getOnlinePlayers().stream()
+ .filter(staff -> staff.hasPermission("hcf.staff"))
+ .forEach(staff -> staff.sendMessage(message));
+
+ player.sendMessage(Locale.COMMAND_REQUEST_SUCCESS.toString());
+ profile.setLastRequestTime(System.currentTimeMillis());
+ }
+
+ /*@Command(label = "vanish", aliases = { "v", "hide" }, permission = "command.vanish", playerOnly = true)
+ public void onVanish(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ if(profile.getModMode() == null)
+ profile.setModMode(new ModMode(p));
+
+ profile.getModMode().setVanished(!profile.getModMode().isVanished());
+ p.sendMessage(Locale.MODMODE_VANISH_TOGGLED.toString().replaceAll("%status%", profile.getModMode().isVanished() ? C.color("&aEnabled") : C.color("&cDisabled")));
+ }*/
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/ModulesCommand.java b/src/main/java/me/hulipvp/hcf/commands/ModulesCommand.java
new file mode 100644
index 0000000..033aa86
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/ModulesCommand.java
@@ -0,0 +1,115 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.modules.Module;
+import me.hulipvp.hcf.api.modules.ex.InvalidModuleException;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.command.CommandSender;
+
+import java.io.File;
+
+public class ModulesCommand {
+
+ @Command(label = "modules", aliases = { "module", "module.list" }, permission = "command.modules")
+ public void onModule(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ sender.sendMessage(C.color("&7Modules: " + (HCF.getInstance().getModuleManager().getModules().size() == 0 ? "&cNone" : "")));
+ for(Module module : HCF.getInstance().getModuleManager().getModules().values())
+ sender.sendMessage(C.color(" &8- " + ((module.isEnabled()) ? "&a" : "&c") + module.getInfo().getName() + " &7(&6" + module.getInfo().getVersion() + "&7)"));
+ }
+
+ @Command(label = "module.load", permission = "command.modules")
+ public void onModuleLoad(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(args.length() < 2) {
+ sender.sendMessage(C.color("&c/module load "));
+ return;
+ }
+
+ String name = args.getArg(1);
+ if(HCF.getInstance().getModuleManager().getModule(name) != null) {
+ sender.sendMessage(C.color("&cThat module is already loaded."));
+ return;
+ }
+
+ File file = new File(HCF.getInstance().getDataFolder() + File.separator + "modules", name + ".jar");
+ if(!file.exists()) {
+ sender.sendMessage(C.color("&cThat module file doesn't exist."));
+ return;
+ }
+
+ try {
+ Module module = HCF.getInstance().getModuleManager().loadModule(file);
+
+ if(HCF.getInstance().getModuleManager().enableModule(module))
+ sender.sendMessage(C.color("&aSuccessfully enabled the module '" + module.getInfo().getName() + "'."));
+ else
+ throw new InvalidModuleException("Module had an issue being enabled, please look for the stacktrace above.");
+ } catch(InvalidModuleException ex) {
+ sender.sendMessage(C.color("&cThere was an error loading module '" + name + "'."));
+ ex.printStackTrace();
+ }
+ }
+
+ @Command(label = "module.unload", permission = "command.modules")
+ public void onModuleUnload(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(args.length() < 2) {
+ sender.sendMessage(C.color("&c/module unload "));
+ return;
+ }
+
+ String name = args.getArg(1);
+ Module module = HCF.getInstance().getModuleManager().getModule(name);
+ if(module == null) {
+ sender.sendMessage(C.color("&cThat module is not loaded."));
+ return;
+ }
+
+ try {
+ HCF.getInstance().getModuleManager().disableModule(module);
+ sender.sendMessage(C.color("&aSuccessfully unloaded '" + module.getInfo().getName() + "'."));
+ } catch(Exception ex) {
+ sender.sendMessage(C.color("&cThere was an error loading module '" + name + "'."));
+ ex.printStackTrace();
+ }
+ }
+
+ @Command(label = "module.reload", permission = "command.modules")
+ public void onModuleReload(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(args.length() < 2) {
+ sender.sendMessage(C.color("&c/module reload "));
+ return;
+ }
+
+ String name = args.getArg(1);
+ Module module = HCF.getInstance().getModuleManager().getModule(name);
+ if(module == null) {
+ sender.sendMessage(C.color("&cThat module is not loaded."));
+ return;
+ }
+
+ File file = new File(HCF.getInstance().getDataFolder() + File.separator + "modules", name + ".jar");
+ if(!file.exists()) {
+ sender.sendMessage(C.color("&cThat module file doesn't exist."));
+ return;
+ }
+
+ try {
+ HCF.getInstance().getModuleManager().disableModule(module);
+ module = HCF.getInstance().getModuleManager().loadModule(file);
+
+ if(HCF.getInstance().getModuleManager().enableModule(module))
+ sender.sendMessage(C.color("&aSuccessfully reloaded module '" + module.getInfo().getName() + "'."));
+ else
+ throw new InvalidModuleException("Module had an issue being enabled, please look for the stacktrace above.");
+ } catch(Exception ex) {
+ sender.sendMessage(C.color("&cThere was an error loading module '" + name + "'."));
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/NotesCommand.java b/src/main/java/me/hulipvp/hcf/commands/NotesCommand.java
new file mode 100644
index 0000000..e6a5811
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/NotesCommand.java
@@ -0,0 +1,123 @@
+package me.hulipvp.hcf.commands;
+
+import com.google.common.base.Joiner;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.player.PlayerUtils;
+import me.hulipvp.hcf.utils.player.UUIDPair;
+import org.apache.commons.lang.StringUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.UUID;
+
+public class NotesCommand {
+
+ @Command(label = "notes", permission = "command.notes")
+ public void onCommand(CommandData args) {
+ switch(args.length()) {
+ case 1: {
+ HCFProfile profile = getProfile(args.getSender(), args.getArg(0));
+ if(profile != null) {
+ args.getSender().sendMessage(Locale.COMMAND_NOTES_PLAYER.toString().replaceAll("%player%", profile.getName()));
+ profile.getNotes().removeIf(note -> {
+ return !note.contains(";");
+ });
+
+ if(profile.getNotes().isEmpty()) {
+ args.getSender().sendMessage(Locale.COMMAND_NOTES_LIST_NONE.toString());
+ } else {
+ for(int i = 0; i < profile.getNotes().size(); i++) {
+ String[] split = profile.getNotes().get(i).split(";");
+ String staffMember = split[0];
+ String message = split[1];
+
+ args.getSender().sendMessage(Locale.COMMAND_NOTES_LIST.toString().replaceAll("%index%", (i + 1) + "").replaceAll("%staffMember%", staffMember).replaceAll("%note%", message));
+ }
+ }
+ }
+ break;
+ }
+ default: {
+ if(args.length() >= 2) {
+ switch(args.getArg(0)) {
+ case "add": {
+ HCFProfile profile = getProfile(args.getSender(), args.getArg(1));
+ if(profile != null) {
+ String staffMember = args.getSender().getName();
+ if(args.length() > 2) {
+ String message = Joiner.on(' ').join(args.getArgs()).replaceFirst("add ", "").replaceFirst(args.getArg(1), "").replaceFirst(" ", "");
+
+ profile.getNotes().add(staffMember + ";" + message);
+ profile.save();
+ args.getSender().sendMessage(C.color("&eAdded note '" + message + "&e'."));
+ } else {
+ args.getSender().sendMessage(C.color("&cUsage: /notes add "));
+ }
+ }
+ break;
+ }
+ case "remove": {
+ HCFProfile profile = getProfile(args.getSender(), args.getArg(1));
+ if(profile != null) {
+ if(args.length() < 2 || !StringUtils.isAlphanumeric(args.getArg(2))) {
+ args.getSender().sendMessage(C.color("&cInvalid index."));
+ return;
+ }
+
+ int index = Integer.valueOf(args.getArg(2)) - 1;
+ if(index < 0 || index > profile.getNotes().size() - 1 || profile.getNotes().isEmpty()) {
+ args.getSender().sendMessage(C.color("&cInvalid index."));
+ return;
+ }
+
+ String note = profile.getNotes().get(index);
+ String message = note.split(";")[1];
+
+ profile.getNotes().remove(index);
+ profile.save();
+ args.getSender().sendMessage(C.color("&eRemoved note '" + message + "&e'."));
+ }
+ break;
+ }
+ default:
+ args.getSender().sendMessage(Locale.COMMAND_NOTES_USAGE.toString());
+ }
+ } else {
+ args.getSender().sendMessage(Locale.COMMAND_NOTES_USAGE.toString());
+ }
+ break;
+ }
+ }
+ }
+
+ private HCFProfile getProfile(CommandSender sender, String target) {
+ String targetName;
+ UUID targetUuid;
+
+ Player targetPlayer = Bukkit.getPlayerExact(target);
+ if(targetPlayer == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(target);
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", target));
+ return null;
+ }
+ } else {
+ targetName = targetPlayer.getName();
+ targetUuid = targetPlayer.getUniqueId();
+ }
+
+ HCFProfile targetProfile = HCFProfile.getByUuid(targetUuid);
+ if(targetProfile.getName() != null)
+ targetProfile.setName(targetName);
+
+ return targetProfile;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/PayCommand.java b/src/main/java/me/hulipvp/hcf/commands/PayCommand.java
new file mode 100644
index 0000000..6558fdc
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/PayCommand.java
@@ -0,0 +1,49 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class PayCommand {
+
+ @Command(label = "pay", playerOnly = true)
+ public void onPayCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() != 2) {
+ p.sendMessage(Locale.COMMAND_PAY_USAGE.toString());
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(0));
+ String rawInt = args.getArg(1);
+ if(target == null) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+
+ if(!StringUtils.isInt(rawInt)) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawInt));
+ return;
+ }
+
+ HCFProfile targetProfile = HCFProfile.getByPlayer(target);
+ int amount = Integer.valueOf(rawInt);
+ if(amount <= 0 || profile.getBalance() < amount) {
+ p.sendMessage(Locale.COMMAND_PAY_NOT_ENOUGH.toString());
+ return;
+ }
+
+ profile.removeFromBalance(amount);
+ targetProfile.addToBalance(amount);
+
+ profile.save();
+ targetProfile.save();
+ p.sendMessage(Locale.COMMAND_PAY_SENT.toString().replaceAll("%recipient%", target.getName()).replaceAll("%amount%", String.valueOf(amount)));
+ target.sendMessage(Locale.COMMAND_PAY_RECEIVED.toString().replaceAll("%sender%", p.getName()).replaceAll("%amount%", String.valueOf(amount)));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/PingCommand.java b/src/main/java/me/hulipvp/hcf/commands/PingCommand.java
new file mode 100644
index 0000000..0e608af
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/PingCommand.java
@@ -0,0 +1,40 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class PingCommand {
+
+ @Command(label = "ping")
+ public void onPing(CommandData args) {
+ Player player = args.getPlayer();
+
+ if(args.getArgs().length >= 1) {
+ Player target = Bukkit.getPlayer(args.getArg(0));
+ if(target != null && target.isOnline())
+ player.sendMessage(Locale.COMMAND_PING_OTHER.toString().replace("%player%", target.getName()).replace("%ping%", getPing(target) + ""));
+ else
+ player.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(0)));
+ } else {
+ player.sendMessage(Locale.COMMAND_PING_SELF.toString().replace("%ping%", getPing(player) + ""));
+ }
+ }
+
+ public static int getPing(Player player) {
+ String nmsVersion = HCF.getInstance().getServer().getClass().getPackage().getName().substring(Bukkit.getServer().getClass().getPackage().getName().lastIndexOf(".") + 1);
+
+ int ping = -1;
+ try {
+ Object nmsPlayer = Class.forName("org.bukkit.craftbukkit." + nmsVersion + ".entity.CraftPlayer").cast(player).getClass().getMethod("getHandle").invoke(player);
+ ping = nmsPlayer.getClass().getField("ping").getInt(nmsPlayer);
+ } catch(Exception e) {
+ HCF.getInstance().getLogger().severe("Could not get ping of player!");
+ e.printStackTrace();
+ }
+ return ping;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/PvpCommand.java b/src/main/java/me/hulipvp/hcf/commands/PvpCommand.java
new file mode 100644
index 0000000..1e020ad
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/PvpCommand.java
@@ -0,0 +1,203 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimer;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimerType;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.player.PlayerUtils;
+import me.hulipvp.hcf.utils.player.UUIDPair;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.util.UUID;
+
+public class PvpCommand {
+
+ @Command(label = "pvp", playerOnly = true)
+ public void onCommand(CommandData args) {
+ this.sendHelp(args.getPlayer());
+ }
+
+ @Command(label = "pvp.enable", playerOnly = true)
+ public void onEnable(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ PlayerTimer timer = profile.getTimerByType(PlayerTimerType.PVPTIMER);
+ if(timer == null && ((timer = profile.getTimerByType(PlayerTimerType.STARTING)) == null)) {
+ p.sendMessage(Locale.COMMAND_PVP_NO_TIMER.toString());
+ return;
+ }
+
+ profile.removeTimersByType(timer.getType());
+ p.sendMessage(Locale.COMMAND_PVP_ENABLED.toString());
+ }
+
+ @Command(label = "pvp.give", permission = "command.pvp", playerOnly = true)
+ public void onGive(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() != 2) {
+ this.sendHelp(p);
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(1));
+ if(target == null) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+
+ HCFProfile profile = HCFProfile.getByPlayer(target);
+ if(profile.getTimerByType(PlayerTimerType.PVPTIMER) != null) {
+ p.sendMessage(Locale.COMMAND_PVP_ALREADY_HAS.toString());
+ return;
+ }
+
+ PlayerTimer timer = new PlayerTimer(target, PlayerTimerType.PVPTIMER);
+ timer.setPaused(true);
+ timer.add();
+ p.sendMessage(Locale.COMMAND_PVP_GIVEN.toString().replaceAll("%player%", target.getName()));
+ }
+ }
+
+ @Command(label = "pvp.remove", permission = "command.pvp", playerOnly = true)
+ public void onRemoveArgument(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() != 2) {
+ this.sendHelp(p);
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(1));
+ if(target == null) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+
+ HCFProfile profile = HCFProfile.getByPlayer(target);
+ PlayerTimer timer = profile.getTimerByType(PlayerTimerType.PVPTIMER);
+ if(timer == null) {
+ p.sendMessage(Locale.COMMAND_PVP_NO_TIMER.toString());
+ return;
+ }
+
+ timer.cancel();
+ profile.removeTimersByType(PlayerTimerType.PVPTIMER);
+ p.sendMessage(Locale.COMMAND_PVP_REMOVED.toString().replaceAll("%player%", target.getName()));
+ }
+ }
+
+ @Command(label = "pvp.set", permission = "command.pvp", playerOnly = true)
+ public void onSetArgument(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() != 3) {
+ this.sendHelp(p);
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(1));
+ String rawInt = args.getArg(2);
+ if(target == null) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+
+ long duration;
+ try {
+ duration = System.currentTimeMillis() - TimeUtils.timeFromString(rawInt, false);
+ } catch(Exception e) {
+ p.sendMessage(Locale.INVALID_TIME.toString()
+ .replaceAll("%number%", rawInt)
+ );
+ return;
+ }
+
+ HCFProfile profile = HCFProfile.getByPlayer(target);
+ PlayerTimer timer = profile.getTimerByType(PlayerTimerType.PVPTIMER);
+ if(timer == null) {
+ timer = new PlayerTimer(target, PlayerTimerType.PVPTIMER);
+ timer.setPaused(true);
+ timer.add();
+ }
+
+ timer.setLength(duration);
+ p.sendMessage(Locale.COMMAND_PVP_SET.toString()
+ .replaceAll("%player%", target.getName())
+ .replaceAll("%time%", TimeUtils.getFormatted(timer.getTimeRemaining(), true, true))
+ );
+ }
+ }
+
+ @Command(label = "pvp.revive", permission = "command.pvp.revive", playerOnly = true)
+ public void onReviveArgument(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() != 2) {
+ this.sendHelp(p);
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(1));
+ String targetName;
+ UUID targetUuid;
+
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(1));
+
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ HCFProfile targetProfile = HCFProfile.getByUuid(targetUuid);
+ if(profile.getLives() > 0)
+ profile.setLives(profile.getLives() - 1);
+
+ if(targetProfile.getBannedTill() != 0) {
+ if(System.currentTimeMillis() < targetProfile.getBannedTill()) {
+ targetProfile.setBannedTill(0);
+ targetProfile.save();
+ p.sendMessage(Locale.COMMAND_REVIVE_SUCCESS.toString().replaceAll("%player%", targetName));
+ return;
+ }
+ }
+
+ p.sendMessage(Locale.COMMAND_REVIVE_NO_DEATHBAN.toString().replaceAll("%player%", targetName));
+ }
+ }
+
+ @Command(label = "pvp.test", permission = "command.pvp.test", playerOnly = true)
+ public void onTest(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getTimerByType(PlayerTimerType.COMBAT) != null) {
+ profile.removeTimersByType(PlayerTimerType.COMBAT);
+ } else {
+ PlayerTimer timer = new PlayerTimer(p, PlayerTimerType.COMBAT);
+ timer.add();
+ }
+ }
+
+ private void sendHelp(Player player) {
+ for(String str : HCF.getInstance().getMessagesFile().getPvpHelp())
+ player.sendMessage(C.color(str
+ .replaceAll("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replaceAll("%secondary%", ConfigValues.SERVER_SECONDARY)
+ .replaceAll("%servername%", ConfigValues.SERVER_NAME)
+ .replaceAll("%servernamelower%", ConfigValues.SERVER_NAME.toLowerCase())
+ .replaceAll("%website%", ConfigValues.SERVER_WEBSITE)
+ .replaceAll("%teamspeak%", ConfigValues.SERVER_TEAMSPEAK)
+ .replaceAll("%store%", ConfigValues.SERVER_STORE))
+ );
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/ReclaimCommand.java b/src/main/java/me/hulipvp/hcf/commands/ReclaimCommand.java
new file mode 100644
index 0000000..1c83938
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/ReclaimCommand.java
@@ -0,0 +1,87 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.backend.files.ReclaimFile;
+import me.hulipvp.hcf.utils.Locale;
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+import java.util.Map;
+
+public class ReclaimCommand {
+
+ private ReclaimFile file;
+
+ public ReclaimCommand() {
+ file = HCF.getInstance().getReclaimFile();
+
+ file.loadGroups();
+ file.loadReclaimed();
+ }
+
+ @Command(label = "reclaim", aliases = { "claim", "claimkeys" }, permission = "command.reclaim", playerOnly = true)
+ public void onReclaim(CommandData args) {
+ Player player = args.getPlayer();
+ if(file.getGroups() == null || file.getGroups().isEmpty()) {
+ player.sendMessage(C.color("&cNo rewards found for reclaim."));
+ return;
+ }
+
+ if(file.getReclaimed().contains(player.getUniqueId().toString())) {
+ player.sendMessage(Locale.RECLAIM_CLAIMED.toString());
+ return;
+ }
+
+ boolean foundGroup = false;
+ for(Map.Entry> group : file.getGroups().entrySet()) {
+ String permission = group.getKey();
+ if(player.hasPermission("reclaim." + permission.toLowerCase())) {
+ foundGroup = true;
+ for(String command : group.getValue())
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replaceAll("%player%", player.getName()));
+
+ player.sendMessage(Locale.RECLAIM_CLAIMED_ITEMS.toString().replaceAll("%rank%", WordUtils.capitalizeFully(permission)));
+ if(file.config.contains("reclaim." + group + ".broadcast"))
+ Bukkit.broadcastMessage(C.color(file.config.getString("reclaim." + group + ".broadcast")).replaceAll("%player%", player.getName()));
+ else
+ Bukkit.broadcastMessage(Locale.RECLAIM_BROADCAST.toString().replaceAll("%player%", player.getName()).replaceAll("%rank%", permission));
+ file.getReclaimed().add(player.getUniqueId().toString());
+ break;
+ }
+ }
+
+ if(!foundGroup)
+ player.sendMessage(Locale.RECLAIM_NO_REWARDS.toString());
+ }
+
+ @Command(label = "resetreclaim", permission = "command.resetreclaim", playerOnly = true)
+ public void onResetReclaim(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(args.length() < 1) {
+ sender.sendMessage(C.color("&cUsage: /resetreclaim "));
+ return;
+ }
+
+ if(args.getArg(0).equalsIgnoreCase("all")) {
+ file.getReclaimed().clear();
+ sender.sendMessage(C.color("&aSuccessfully reset everyone's reclaim."));
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(0));
+ if(target == null || !target.isOnline()) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ return;
+ }
+
+ if(file.getReclaimed().remove(target.getUniqueId().toString()))
+ sender.sendMessage(C.color("&aSuccessfully reset " + target.getName() + "'s reclaim."));
+ else
+ sender.sendMessage(C.color("&cThe player '" + target.getName() + "' has not reclaimed anything yet."));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/ResetDataCommand.java b/src/main/java/me/hulipvp/hcf/commands/ResetDataCommand.java
new file mode 100644
index 0000000..b13d8de
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/ResetDataCommand.java
@@ -0,0 +1,145 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.backend.backends.MongoBackend;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TaskUtils;
+import me.hulipvp.hcf.utils.player.PlayerUtils;
+import me.hulipvp.hcf.utils.player.UUIDPair;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.UUID;
+
+public class ResetDataCommand {
+
+ @Command(label = "resetdata", permission = "command.resetdata")
+ public void onCommand(CommandData args) {
+ sendUsage(args.getSender());
+ }
+
+ @Command(label = "resetdata.factions", permission = "command.resetdata")
+ public void onFactions(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ sender.sendMessage(C.color("&aAttempting to reset all faction data..."));
+
+ TaskUtils.runAsync(() -> {
+ HCF.getInstance().getBackend().deleteFactions();
+ HCFProfile.getProfiles().values().forEach(profile -> {
+ profile.setFaction(null);
+ profile.save();
+ });
+
+ Faction.getFactions().clear();
+ Faction.getClaimPositions().clear();
+
+ HCF.getInstance().getBackend().deleteFactions();
+
+ Mountain.getMountains().values().forEach(HCF.getInstance().getBackend()::deleteMountain);
+ Conquest.getConquests().values().forEach(HCF.getInstance().getBackend()::deleteConquest);
+ Koth.getKoths().values().forEach(HCF.getInstance().getBackend()::deleteKoth);
+
+ Mountain.getMountains().clear();
+ Conquest.getConquests().clear();
+ Koth.getKoths().clear();
+
+ sender.sendMessage(C.color("&aFaction data has been cleared!"));
+ });
+ }
+
+ @Command(label = "resetdata.profiles", permission = "command.resetdata")
+ public void onProfiles(CommandData args) {
+ CommandSender sender = args.getSender();
+
+ sender.sendMessage(C.color("&aAttempting to reset all profile data..."));
+ Bukkit.getOnlinePlayers().forEach(player -> {
+ player.kickPlayer(C.color("&cResetting all profile data!"));
+ });
+
+ TaskUtils.runAsync(() -> {
+ HCF.getInstance().getBackend().loadProfiles();
+ HCFProfile.getProfiles().values().forEach(profile -> {
+ profile.reset();
+ profile.save();
+ });
+
+ sender.sendMessage(C.color("&aProfile data has been cleared!"));
+ });
+ }
+
+ @Command(label = "resetdata.profile", permission = "command.resetdata")
+ public void onProfile(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(args.length() < 2) {
+ sender.sendMessage(C.color("&cUsage: /resetdata profile "));
+ return;
+ }
+
+ Player target = Bukkit.getPlayerExact(args.getArg(1));
+ String targetName;
+ UUID targetUuid;
+ HCFProfile profile;
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(1));
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ sender.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(1)));
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ profile = HCFProfile.getByUuid(targetUuid);
+
+ sender.sendMessage(C.color("&aAttempting to reset data of '" + targetName + "'."));
+ /*if(profile.hasFaction()) {
+ PlayerFaction faction = profile.getFactionObj();
+ faction.getMembers().remove(profile.getUuid());
+
+ faction.getMembers().keySet().stream()
+ .map(Bukkit::getPlayer)
+ .filter(Objects::nonNull)
+ .filter(Player::isOnline)
+ .forEach(HCFTablist::update);
+ }*/
+
+ profile.reset();
+ profile.save();
+
+ sender.sendMessage(C.color("&aProfile data of '" + targetName + "' has been cleared!"));
+ }
+
+ @Command(label = "resetdata.revives", permission = "command.resetdata")
+ public void onRevives(CommandData args) {
+ CommandSender sender = args.getSender();
+ sender.sendMessage(C.color("&aAttempting to reset everyone's revive cooldown..."));
+
+ TaskUtils.runAsync(() -> {
+ HCF.getInstance().getBackend().loadProfiles();
+ HCFProfile.getProfiles().values().forEach(profile -> {
+ profile.setLastRevive(0L);
+ profile.save();
+ });
+
+ sender.sendMessage(C.color("&aRevives have been reset!"));
+ });
+ }
+
+ private void sendUsage(CommandSender sender) {
+ sender.sendMessage(C.color("&cUsage: /resetdata "));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/RestoreInventoryCommand.java b/src/main/java/me/hulipvp/hcf/commands/RestoreInventoryCommand.java
new file mode 100644
index 0000000..2fa80fe
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/RestoreInventoryCommand.java
@@ -0,0 +1,44 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.player.data.Death;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class RestoreInventoryCommand {
+
+ @Command(label = "restoreinventory", permission = "command.restore", aliases = {"restoreinv"}, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() != 1) {
+ p.sendMessage(Locale.COMMAND_RESTORE_USAGE.toString());
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(0));
+ if(target == null) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ return;
+ }
+
+ HCFProfile targetProfile = HCFProfile.getByPlayer(target);
+ if(targetProfile.getDeaths().size() == 0) {
+ p.sendMessage(Locale.COMMAND_RESTORE_NOT_FOUND.toString().replaceAll("%player%", target.getName()));
+ return;
+ }
+
+ Bukkit.getScheduler().runTaskLater(HCF.getInstance(), () -> {
+ Death death = targetProfile.getDeaths().get(targetProfile.getDeaths().size() - 1);
+ target.getInventory().setArmorContents(death.getInv().getArmor());
+ target.getInventory().setContents(death.getInv().getItems());
+ target.updateInventory();
+
+ p.sendMessage(Locale.COMMAND_RESTORE_SUCCESS.toString().replaceAll("%player%", target.getName()));
+ target.sendMessage(Locale.COMMAND_RESTORE_RESTORED.toString().replaceAll("%restorer%", p.getName()));
+ }, 1L);
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/SetCommand.java b/src/main/java/me/hulipvp/hcf/commands/SetCommand.java
new file mode 100644
index 0000000..e31aa0f
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/SetCommand.java
@@ -0,0 +1,54 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.entity.Player;
+
+public class SetCommand {
+
+ @Command(label = "setendspawn", permission = "command.setendspawn", playerOnly = true)
+ public void onSetEndSpawn(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ HCF.getInstance().getLocationsFile().setEndSpawn(p.getLocation());
+ if(HCF.getInstance().getLocationsFile().save())
+ p.sendMessage(Locale.COMMAND_SETENDSPAWN_SUCCESS.toString());
+ else
+ p.sendMessage(Locale.COMMAND_SETENDSPAWN_FAILURE.toString());
+ }
+
+ @Command(label = "setendexit", permission = "command.setendexit", playerOnly = true)
+ public void onSetEndExit(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ HCF.getInstance().getLocationsFile().setEndExit(p.getLocation());
+ if(HCF.getInstance().getLocationsFile().save())
+ p.sendMessage(Locale.COMMAND_SETENDEXIT_SUCCESS.toString());
+ else
+ p.sendMessage(Locale.COMMAND_SETENDEXIT_FAILURE.toString());
+ }
+
+ @Command(label = "setnetherspawn", permission = "command.setnetherspawn", playerOnly = true)
+ public void onSetNetherSpawn(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ HCF.getInstance().getLocationsFile().setNetherSpawn(p.getLocation());
+ if(HCF.getInstance().getLocationsFile().save())
+ p.sendMessage(Locale.COMMAND_SETNETHERSPAWN_SUCCESS.toString());
+ else
+ p.sendMessage(Locale.COMMAND_SETNETHERSPAWN_FAILURE.toString());
+ }
+
+ @Command(label = "setnetherexit", permission = "command.setnetherexit", playerOnly = true)
+ public void onSetNetherExit(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ HCF.getInstance().getLocationsFile().setNetherExit(p.getLocation());
+ if(HCF.getInstance().getLocationsFile().save())
+ p.sendMessage(Locale.COMMAND_SETNETHEREXIT_SUCCESS.toString());
+ else
+ p.sendMessage(Locale.COMMAND_SETNETHEREXIT_FAILURE.toString());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/SetMaxPlayersCommand.java b/src/main/java/me/hulipvp/hcf/commands/SetMaxPlayersCommand.java
new file mode 100644
index 0000000..4addd4d
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/SetMaxPlayersCommand.java
@@ -0,0 +1,48 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.lang.reflect.Field;
+
+public class SetMaxPlayersCommand {
+
+ @Command(label = "setmaxplayers", aliases = {"smp"}, permission = "command.setmaxplayers", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player player = args.getPlayer();
+ if(args.length() != 1) {
+ player.sendMessage(C.color("&cUsage: /smp "));
+ return;
+ }
+
+ if(!StringUtils.isInt(args.getArg(0))) {
+ player.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", args.getArg(0)));
+ return;
+ }
+
+ int amount = Integer.parseInt(args.getArg(0));
+ try {
+ setMaxPlayers(amount);
+ } catch(ReflectiveOperationException e) {
+ player.sendMessage(C.color("&cError while attempting to set max players."));
+ return;
+ }
+
+ player.sendMessage(C.color("&aSet max players to " + amount + "."));
+ }
+
+ private void setMaxPlayers(int max)
+ throws ReflectiveOperationException {
+ String bukkitVersion = Bukkit.getServer().getClass().getPackage().getName().substring(23);
+ Object playerList = Class.forName("org.bukkit.craftbukkit." + bukkitVersion + ".CraftServer").getDeclaredMethod("getHandle", (Class>[]) null).invoke(Bukkit.getServer(), (Object[]) null);
+ Field maxPlayers = playerList.getClass().getSuperclass().getDeclaredField("maxPlayers");
+
+ maxPlayers.setAccessible(true);
+ maxPlayers.set(playerList, max);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/SettingsCommand.java b/src/main/java/me/hulipvp/hcf/commands/SettingsCommand.java
new file mode 100644
index 0000000..fdb1867
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/SettingsCommand.java
@@ -0,0 +1,34 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.player.data.setting.HCFSetting;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+
+public class SettingsCommand {
+
+ @Command(label = "settings", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player player = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ openSettings(player, profile);
+ }
+
+ private void openSettings(Player player, HCFProfile profile) {
+ String title = ConfigValues.SETTINGS_GUI_TITLE
+ .replaceAll("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replaceAll("%secondary%", ConfigValues.SERVER_SECONDARY);
+
+ Inventory settings = Bukkit.createInventory(null, 9, C.color(title));
+ for(HCFSetting setting : profile.getSettings())
+ settings.setItem(setting.getType().getSlot(), setting.getSettingItem());
+
+ player.openInventory(settings);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/SotwCommand.java b/src/main/java/me/hulipvp/hcf/commands/SotwCommand.java
new file mode 100644
index 0000000..62c5bdd
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/SotwCommand.java
@@ -0,0 +1,113 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.timer.Timer;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimer;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimerType;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+
+import java.util.concurrent.TimeUnit;
+
+public class SotwCommand {
+
+ @Command(label = "sotw", permission = "command.sotw")
+ public void onSotw(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(ConfigValues.LISTENERS_STARTING_TIMER) {
+ sender.sendMessage(C.color("&cPlease disable the 'starting-timer' option in the config.yml in order to use /sotw"));
+ return;
+ }
+
+ sender.sendMessage(Locale.COMMAND_SOTW_USAGE.toString());
+ }
+
+ @Command(label = "sotw.start", permission = "command.sotw")
+ public void onStart(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(ConfigValues.LISTENERS_STARTING_TIMER) {
+ sender.sendMessage(C.color("&cPlease disable the 'starting-timer' option in the config.yml in order to use /sotw"));
+ return;
+ }
+
+ ServerTimer sotw = getSotw();
+ if(sotw != null) {
+ sender.sendMessage(Locale.COMMAND_SOTW_RUNNING.toString());
+ return;
+ }
+
+ if(args.length() < 2) {
+ sender.sendMessage(Locale.COMMAND_SOTW_USAGE.toString());
+ return;
+ }
+
+
+ long expiry = -1;
+ try {
+ expiry = TimeUtils.timeFromString(args.getArg(1), true);
+ } catch(Exception ex) { }
+
+ if(expiry <= 0) {
+ sender.sendMessage(C.color("&cInvalid time. Ex: 10m"));
+ return;
+ }
+
+ long length = expiry - System.currentTimeMillis();
+
+ ServerTimer timer = new ServerTimer(ServerTimerType.SOTW);
+ timer.setNewLength(TimeUnit.MILLISECONDS.toSeconds(length));
+ timer.add();
+
+ Bukkit.broadcastMessage(Locale.COMMAND_SOTW_STARTED.toString());
+ }
+
+ @Command(label = "sotw.stop", permission = "command.sotw")
+ public void onStop(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(ConfigValues.LISTENERS_STARTING_TIMER) {
+ sender.sendMessage(C.color("&cPlease disable the 'starting-timer' option in the config.yml in order to use /sotw"));
+ return;
+ }
+
+ ServerTimer sotw = getSotw();
+ if(sotw == null) {
+ sender.sendMessage(Locale.COMMAND_SOTW_NOT_RUNNING.toString());
+ return;
+ }
+
+ Timer.getTimers().remove(sotw.getUuid());
+
+ Bukkit.broadcastMessage(Locale.COMMAND_SOTW_STOPPED.toString());
+ }
+
+ @Command(label = "sotw.pause", permission = "command.sotw")
+ public void onPause(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(ConfigValues.LISTENERS_STARTING_TIMER) {
+ sender.sendMessage(C.color("&cPlease disable the 'starting-timer' option in the config.yml in order to use /sotw"));
+ return;
+ }
+
+ ServerTimer sotw = getSotw();
+ if(sotw == null) {
+ sender.sendMessage(Locale.COMMAND_SOTW_NOT_RUNNING.toString());
+ return;
+ }
+
+ sotw.setPaused(!sotw.isPaused());
+
+ if(sotw.isPaused())
+ Bukkit.broadcastMessage(Locale.COMMAND_SOTW_PAUSED.toString());
+ else
+ Bukkit.broadcastMessage(Locale.COMMAND_SOTW_UNPAUSED.toString());
+ }
+
+ private ServerTimer getSotw() {
+ return ServerTimer.getTimer(ServerTimerType.SOTW);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/SpawnCommand.java b/src/main/java/me/hulipvp/hcf/commands/SpawnCommand.java
new file mode 100644
index 0000000..c466078
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/SpawnCommand.java
@@ -0,0 +1,44 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.system.SafezoneFaction;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+public class SpawnCommand {
+
+ @Command(label = "spawn", permission = "command.spawn", playerOnly = true)
+ public void onSpawn(CommandData args) {
+ Player p = (Player) args.getSender();
+ Faction spawn = Faction.getByName("Spawn");
+
+ if(spawn != null && spawn.getHome() != null)
+ p.teleport(spawn.getHome());
+ else
+ p.sendMessage(Locale.COMMAND_SPAWN.toString());
+ }
+
+ @Command(label = "setspawn", permission = "command.setspawn", playerOnly = true)
+ public void onSetSpawn(CommandData args) {
+ Player player = (Player) args.getSender();
+ Faction spawn = Faction.getByName("Spawn");
+ if(!(spawn instanceof SafezoneFaction)) {
+ player.sendMessage(ChatColor.RED + "Please type /instatehcf to create default factions and then set the spawn/");
+ return;
+ }
+
+ if(!spawn.isInsideClaim(player.getLocation())) {
+ player.sendMessage(C.color("&ePlease stand inside of the " + ((SafezoneFaction) spawn).getColoredName() + " &efaction to set the spawn point."));
+ return;
+ }
+
+ spawn.setHome(player.getLocation());
+ spawn.save();
+
+ player.sendMessage(ChatColor.GREEN + "Spawn point successfully set.");
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/StaffReviveCommand.java b/src/main/java/me/hulipvp/hcf/commands/StaffReviveCommand.java
new file mode 100644
index 0000000..3627d34
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/StaffReviveCommand.java
@@ -0,0 +1,56 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.player.PlayerUtils;
+import me.hulipvp.hcf.utils.player.UUIDPair;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.util.UUID;
+
+public class StaffReviveCommand {
+
+ @Command(label = "staffrevive", permission = "command.revive", aliases = {"revive"}, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() != 1) {
+ p.sendMessage(Locale.COMMAND_REVIVE_USAGE.toString());
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(0));
+ String targetName;
+ UUID targetUuid;
+ HCFProfile profile;
+
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(0));
+
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ p.sendMessage(Locale.MOJANG_API_FAIL.toString());
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ profile = HCFProfile.getByUuid(targetUuid);
+
+ if(profile.getBannedTill() != 0) {
+ if(System.currentTimeMillis() < profile.getBannedTill()) {
+ profile.setBannedTill(0);
+ profile.save();
+ p.sendMessage(Locale.COMMAND_REVIVE_SUCCESS.toString().replaceAll("%player%", targetName));
+ return;
+ }
+ }
+ p.sendMessage(Locale.COMMAND_REVIVE_NO_DEATHBAN.toString().replaceAll("%player%", targetName));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/StatsCommand.java b/src/main/java/me/hulipvp/hcf/commands/StatsCommand.java
new file mode 100644
index 0000000..c47b2d3
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/StatsCommand.java
@@ -0,0 +1,137 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.player.data.Death;
+import me.hulipvp.hcf.game.player.data.Kill;
+import me.hulipvp.hcf.game.player.data.statistic.HCFStatistic;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.item.InvUtils;
+import me.hulipvp.hcf.utils.item.ItemBuilder;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.SkullMeta;
+
+public class StatsCommand {
+
+ @Command(label = "stats", aliases = { "ores" }, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ Player target;
+ HCFProfile profile;
+
+ if(args.length() != 1) {
+ target = args.getPlayer();
+ } else {
+ target = Bukkit.getPlayer(args.getArg(0));
+ if(target == null) {
+ args.getPlayer().sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ return;
+ }
+ }
+
+ profile = HCFProfile.getByPlayer(target);
+ p.openInventory(this.getStatistics(target, profile));
+ }
+
+ private Inventory getStatistics(Player target, HCFProfile profile) {
+ Inventory inventory = Bukkit.createInventory(null, 36, C.color(ConfigValues.SERVER_SECONDARY + target.getName() + ConfigValues.SERVER_PRIMARY + "'s Statistics"));
+ InvUtils.fillSidesWithItem(inventory, new ItemStack(Material.STAINED_GLASS_PANE, 1, (short) 14));
+
+ for(HCFStatistic statistic : profile.getStatistics()) {
+ ItemStack itemStack = new ItemBuilder(statistic.getType().getMaterial())
+ .amount(1)
+ .name("&b&l" + WordUtils.capitalizeFully(statistic.getType().name().replace("_", " ").toLowerCase()))
+ .lore("&eAmount: &a" + statistic.getValue()).get();
+
+ inventory.addItem(itemStack);
+ }
+
+ inventory.setItem(19, new ItemBuilder(Material.DIAMOND_SWORD)
+ .amount(1)
+ .name("&a&lKills")
+ .lore("&eAmount: &a" + profile.getKills().size(), " ", "&7Click to show recent kills.").get());
+
+ inventory.setItem(25, new ItemBuilder(Material.SKULL_ITEM)
+ .amount(1)
+ .name("&c&lDeaths")
+ .lore("&eAmount: &a" + profile.getDeaths().size(), " ", "&7Click to show recent deaths.").get());
+
+ return inventory;
+ }
+
+ public static void openDeathsInventory(Player target) {
+ Inventory inventory = Bukkit.createInventory(null, 45, C.color(ConfigValues.SERVER_SECONDARY + target.getName() + ConfigValues.SERVER_PRIMARY + "'s Recent Deaths"));
+ HCFProfile profile = HCFProfile.getByPlayer(target);
+
+ int index = 0;
+ for(Death death : profile.getDeaths()) {
+ ItemStack skull = new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
+ SkullMeta skullMeta = (SkullMeta) skull.getItemMeta();
+ if(death.getKiller() != null) {
+ HCFProfile deadProfile = HCFProfile.getByUuid(death.getKiller());
+ if(deadProfile.getName() != null) {
+ skullMeta.setOwner(target.getName());
+ skullMeta.setDisplayName(ChatColor.AQUA + "Unknown Killer");
+ } else {
+ skullMeta.setOwner(deadProfile.getName());
+ skullMeta.setDisplayName(ChatColor.AQUA + deadProfile.getName());
+ }
+ } else {
+ skullMeta.setOwner(target.getName());
+ skullMeta.setDisplayName(ChatColor.AQUA + "Unknown Killer");
+ }
+
+ skull.setItemMeta(skullMeta);
+
+ inventory.addItem(skull);
+ index++;
+ if(index >= inventory.getSize())
+ break;
+ }
+
+ target.openInventory(inventory);
+ }
+
+ public static void openKillsInventory(Player target) {
+ Inventory inventory = Bukkit.createInventory(null, 45, C.color(ConfigValues.SERVER_SECONDARY + target.getName() + ConfigValues.SERVER_PRIMARY + "'s Recent Kills"));
+ HCFProfile profile = HCFProfile.getByPlayer(target);
+
+ int index = 0;
+ for(Kill kill : profile.getKills()) {
+ ItemStack skull = new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
+ SkullMeta skullMeta = (SkullMeta) skull.getItemMeta();
+ if(kill.getKilled() != null) {
+ HCFProfile killedProfile = HCFProfile.getByUuid(kill.getKilled());
+ if(killedProfile.getName() != null) {
+ skullMeta.setOwner(target.getName());
+ skullMeta.setDisplayName(ChatColor.AQUA + "Unknown Killed");
+ } else {
+ skullMeta.setOwner(killedProfile.getName());
+ skullMeta.setDisplayName(ChatColor.AQUA + killedProfile.getName());
+ }
+ } else {
+ skullMeta.setOwner(target.getName());
+ skullMeta.setDisplayName(ChatColor.AQUA + "Unknown Killed");
+ }
+
+ skull.setItemMeta(skullMeta);
+
+ inventory.addItem(skull);
+ index++;
+ if(index >= inventory.getSize())
+ break;
+ }
+
+ target.openInventory(inventory);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/TeleportCommand.java b/src/main/java/me/hulipvp/hcf/commands/TeleportCommand.java
new file mode 100644
index 0000000..2f46dab
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/TeleportCommand.java
@@ -0,0 +1,87 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+
+public class TeleportCommand {
+
+ @Command(label = "tp", aliases = { "teleport", "tppos" }, permission = "command.tp", playerOnly = true)
+ public void onTp(CommandData args) {
+ Player player = (Player) args.getSender();
+
+ if(args.length() == 1) {
+ Player target = Bukkit.getPlayerExact(args.getArg(0));
+ if(target != null) {
+ player.teleport(target.getLocation());
+ player.sendMessage(Locale.TELEPORT_PLAYER_ONLINE.toString().replaceAll("%name%", target.getName()));
+ } else {
+ player.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ }
+ } else if(args.length() == 3) {
+ Integer x = null;
+ Integer y = null;
+ Integer z = null;
+
+ try {
+ x = Integer.parseInt(args.getArg(0));
+ y = Integer.parseInt(args.getArg(1));
+ z = Integer.parseInt(args.getArg(2));
+ } catch(NumberFormatException e) {
+ String number = ((x == null) ? args.getArg(0) : ((y == null) ? args.getArg(1) : args.getArg(2)));
+ player.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", number));
+ return;
+ }
+
+ player.teleport(new Location(player.getWorld(), x, y, z));
+ player.sendMessage(Locale.TELEPORT_LOCATION.toString().replaceAll("%x%", String.valueOf(x)).replaceAll("%y%", String.valueOf(y)).replaceAll("%z%", String.valueOf(z)));
+ } else {
+ player.sendMessage(C.color("&cUsage: /tp OR /tp "));
+ }
+ }
+
+ @Command(label = "tphere", aliases = { "teleporthere", "s" }, permission = "command.tphere", playerOnly = true)
+ public void onTpHere(CommandData args) {
+ Player player = (Player) args.getSender();
+
+ if(args.length() == 1) {
+ Player target = Bukkit.getPlayerExact(args.getArg(0));
+ if(target != null) {
+ target.teleport(player.getLocation());
+ player.sendMessage(Locale.TELEPORT_PLAYER_HERE.toString().replaceAll("%name%", target.getName()).replaceAll("%you%", player.getName()));
+ } else {
+ player.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replaceAll("%name%", args.getArg(0)));
+ }
+ } else {
+ player.sendMessage(C.color("&cUsage: /tphere "));
+ }
+ }
+
+ @Command(label = "tpall", aliases = { "teleportall" }, permission = "command.tpall", playerOnly = true)
+ public void onTpAll(CommandData args) {
+ Player player = args.getPlayer();
+ player.sendMessage(Locale.TELEPORT_ALL.toString());
+
+ for(Player other : Bukkit.getOnlinePlayers()) {
+ if(other == player)
+ continue;
+
+ other.teleport(player);
+ }
+ }
+
+ @Command(label = "top", permission = "command.top", playerOnly = true)
+ public void onTop(CommandData args) {
+ Player player = args.getPlayer();
+
+ Location top = player.getLocation().clone();
+ top.setY(player.getWorld().getHighestBlockYAt(player.getLocation()));
+
+ player.teleport(top);
+ player.sendMessage(Locale.TELEPORT_TOP.toString());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/TimerCommand.java b/src/main/java/me/hulipvp/hcf/commands/TimerCommand.java
new file mode 100644
index 0000000..4362670
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/TimerCommand.java
@@ -0,0 +1,68 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.timer.Timer;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimer;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimerType;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+
+import java.util.concurrent.TimeUnit;
+
+public class TimerCommand {
+
+ @Command(label = "keysale", permission = "command.keysale")
+ public void onKeySale(CommandData args) {
+ CommandSender sender = args.getSender();
+ if(args.length() < 1) {
+ sender.sendMessage(Locale.COMMAND_KEY_SALE_USAGE.toString());
+ return;
+ }
+
+ ServerTimer keySale = getKeySale();
+ if(keySale != null) {
+ sender.sendMessage(Locale.COMMAND_KEY_SALE_RUNNING.toString());
+ return;
+ }
+
+ long expiry = -1;
+ try {
+ expiry = TimeUtils.timeFromString(args.getArg(0), true);
+ } catch(Exception ex) { }
+
+ if(expiry <= 0) {
+ sender.sendMessage(C.color("&cInvalid time. Ex: 10m"));
+ return;
+ }
+
+ long length = expiry - System.currentTimeMillis();
+
+ ServerTimer timer = new ServerTimer(ServerTimerType.KEY_SALE);
+ timer.setNewLength(TimeUnit.MILLISECONDS.toSeconds(length));
+ timer.add();
+
+ Bukkit.broadcastMessage(Locale.COMMAND_KEY_SALE_STARTED.toString());
+ }
+
+ @Command(label = "keysale.stop", permission = "command.keysale")
+ public void onKeySaleStop(CommandData args) {
+ CommandSender sender = args.getSender();
+ ServerTimer keySale = getKeySale();
+ if(keySale == null) {
+ sender.sendMessage(Locale.COMMAND_KEY_SALE_NOT_RUNNING.toString());
+ return;
+ }
+
+ Timer.getTimers().remove(keySale.getUuid());
+
+ Bukkit.broadcastMessage(Locale.COMMAND_KEY_SALE_STOPPED.toString());
+ }
+
+ private ServerTimer getKeySale() {
+ return ServerTimer.getTimer(ServerTimerType.KEY_SALE);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/commands/ToggleChatCommand.java b/src/main/java/me/hulipvp/hcf/commands/ToggleChatCommand.java
new file mode 100644
index 0000000..fa812b7
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/commands/ToggleChatCommand.java
@@ -0,0 +1,72 @@
+package me.hulipvp.hcf.commands;
+
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.player.data.ChatMode;
+import me.hulipvp.hcf.game.player.data.setting.SettingType;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class ToggleChatCommand {
+
+ @Command(label = "tgc", aliases = { "toggleglobalchat" }, playerOnly = true)
+ public void onToggleGlobal(CommandData args) {
+ HCFProfile profile = HCFProfile.getByPlayer(args.getPlayer());
+
+ profile.getSetting(SettingType.PUBLIC_CHAT).toggle();
+ if(profile.getSetting(SettingType.PUBLIC_CHAT).getValue())
+ args.getPlayer().sendMessage(Locale.COMMAND_CHAT_ENABLED.toString());
+ else
+ args.getPlayer().sendMessage(Locale.COMMAND_CHAT_DISABLED.toString());
+ }
+
+ @Command(label = "gc", aliases = { "globalchat" }, playerOnly = true)
+ public void onGlobalChat(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ profile.setChatMode(ChatMode.PUBLIC);
+ player.sendMessage(Locale.COMMAND_FACTION_CHAT_CHANGED.toString().replaceAll("%mode%", ChatMode.PUBLIC.getDisplay()));
+ }
+
+ @Command(label = "tc", aliases = { "teamchat" }, playerOnly = true)
+ public void onTeamChat(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ if(profile.getFactionObj() != null)
+ profile.setChatMode(ChatMode.FACTION);
+ else
+ profile.setChatMode(ChatMode.PUBLIC);
+
+ player.sendMessage(Locale.COMMAND_FACTION_CHAT_CHANGED.toString().replaceAll("%mode%", ChatMode.FACTION.getDisplay()));
+ }
+
+ @Command(label = "ac", aliases = { "allychat" }, playerOnly = true)
+ public void onAllyChat(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ if(profile.getFactionObj() != null)
+ profile.setChatMode(ChatMode.ALLY);
+ else
+ profile.setChatMode(ChatMode.PUBLIC);
+
+ player.sendMessage(Locale.COMMAND_FACTION_CHAT_CHANGED.toString().replaceAll("%mode%", ChatMode.ALLY.getDisplay()));
+ }
+
+ @Command(label = "oc", aliases = { "officerchat" }, playerOnly = true)
+ public void onOfficerChat(CommandData args) {
+ Player player = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ if(profile.getFactionObj() != null && profile.getFactionObj().getMembers().get(profile.getUuid()).isAtLeast(FactionRank.CAPTAIN))
+ profile.setChatMode(ChatMode.CAPTAIN);
+ else
+ profile.setChatMode(ChatMode.PUBLIC);
+
+ player.sendMessage(Locale.COMMAND_FACTION_CHAT_CHANGED.toString().replaceAll("%mode%", ChatMode.CAPTAIN.getDisplay()));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/conquest/Conquest.java b/src/main/java/me/hulipvp/hcf/game/event/conquest/Conquest.java
new file mode 100644
index 0000000..66df597
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/conquest/Conquest.java
@@ -0,0 +1,122 @@
+package me.hulipvp.hcf.game.event.conquest;
+
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.events.conquest.ConquestEndEvent;
+import me.hulipvp.hcf.api.events.conquest.ConquestStartEvent;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestEndReason;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestZone;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestZoneType;
+import me.hulipvp.hcf.game.faction.type.event.ConquestFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import org.bson.Document;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class Conquest {
+
+ @Getter private static final Map conquests = new HashMap<>();
+ @Getter @Setter private static Conquest activeConquest;
+
+ @Getter private final String name;
+ @Getter @Setter private ConquestFaction faction;
+ @Getter private final Map zones;
+ @Getter private final Map points;
+ @Getter @Setter private UUID finalCapper;
+
+ public Conquest(String name) {
+ this.name = name;
+ this.faction = null;
+ this.zones = new HashMap<>();
+ this.zones.put(ConquestZoneType.RED, new ConquestZone(null, null, ConquestZoneType.RED));
+ this.zones.put(ConquestZoneType.YELLOW, new ConquestZone(null, null, ConquestZoneType.YELLOW));
+ this.zones.put(ConquestZoneType.GREEN, new ConquestZone(null, null, ConquestZoneType.GREEN));
+ this.zones.put(ConquestZoneType.BLUE, new ConquestZone(null, null, ConquestZoneType.BLUE));
+ this.points = new HashMap<>();
+ this.finalCapper = null;
+ }
+
+ public void start() {
+ setActiveConquest(this);
+
+ ConquestStartEvent event = new ConquestStartEvent(this);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ }
+
+ public void stop() {
+ if(getActiveConquest() == this) {
+ setActiveConquest(null);
+
+ ConquestEndEvent event = new ConquestEndEvent(this, ConquestEndReason.CANCELLED);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ }
+ }
+
+ public void save() {
+ HCF.getInstance().getBackend().saveConquest(this);
+ }
+
+ public ConquestZone getZoneAt(Location location) {
+ for(ConquestZone zone : this.getZones().values()) {
+ if(zone.toCuboid() == null)
+ continue;
+
+ if(zone.toCuboid().isInCuboid(location))
+ return zone;
+ }
+
+ return null;
+ }
+
+ public static Conquest getConquest(String name) {
+ return getConquests().get(name);
+ }
+
+ public Document toDocument() {
+ return new Document()
+ .append("name", this.getName())
+ .append("faction", (this.getFaction() == null) ? null : this.getFaction().getUuid().toString())
+ .append("red", this.getZones().get(ConquestZoneType.RED).toString())
+ .append("yellow", this.getZones().get(ConquestZoneType.YELLOW).toString())
+ .append("green", this.getZones().get(ConquestZoneType.GREEN).toString())
+ .append("blue", this.getZones().get(ConquestZoneType.BLUE).toString());
+ }
+
+ public static void instate() {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if(getActiveConquest() == null)
+ return;
+
+ Conquest conquest = getActiveConquest();
+ for(ConquestZone zone : conquest.getZones().values()) {
+ if(zone.getCapper() != null) {
+ zone.lowerTimer();
+
+ if(zone.getTimer() <= 20L) {
+ zone.resetTimer();
+
+ HCFProfile capper = HCFProfile.getByUuid(zone.getCapper());
+ int points = ((conquest.getPoints().containsKey(capper.getFaction().toString())) ? conquest.getPoints().get(capper.getFaction().toString()) : 0) + ConfigValues.CONQUEST_POINTS_PER_CAP;
+ conquest.getPoints().put(capper.getFaction().toString(), points);
+ Bukkit.broadcastMessage(Locale.EVENT_CONQUEST_CAPPED.toString()
+ .replaceAll("%zone%", zone.getType().getDisplay())
+ .replaceAll("%name%", capper.getFactionObj().getName()));
+ }
+ } else {
+ zone.resetTimer();
+ }
+ }
+ }
+ }.runTaskTimerAsynchronously(HCF.getInstance(), 2L, 20L);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/conquest/command/ConquestCommand.java b/src/main/java/me/hulipvp/hcf/game/event/conquest/command/ConquestCommand.java
new file mode 100644
index 0000000..5aa8e1b
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/conquest/command/ConquestCommand.java
@@ -0,0 +1,211 @@
+package me.hulipvp.hcf.game.event.conquest.command;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.api.command.Completer;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestZone;
+import me.hulipvp.hcf.game.event.conquest.data.ConquestZoneType;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.event.ConquestFaction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ConquestCommand {
+
+ @Command(label = "conquest", permission = "command.conquest", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ Conquest conquest;
+
+ switch(args.length()) {
+ case 1:
+ if(Conquest.getConquest(args.getArg(0)) != null) {
+ conquest = Conquest.getConquest(args.getArg(0));
+
+ p.sendMessage(C.color(conquest.getFaction().getColoredName() + "&7:"));
+ p.sendMessage(C.color(" &eName: &f" + conquest.getName()));
+ p.sendMessage(C.color(" &eActive: &f" + ((Conquest.getActiveConquest() == conquest) ? "&aTrue" : "&cFalse")));
+ } else {
+ p.sendMessage(Locale.COMMAND_CONQUEST_DOESNT_EXIST.toString().replaceAll("%conquest%", args.getArg(0)));
+ p.sendMessage(Locale.COMMAND_CONQUEST_DOESNT_EXIST_SUBTEXT.toString().replaceAll("%conquest%", args.getArg(0)));
+ }
+ return;
+ case 2:
+ if(args.getArg(1).toLowerCase().equals("create")) {
+ if(Faction.getByName(args.getArg(0)) != null) {
+ p.sendMessage(Locale.COMMAND_CONQUEST_ALREADY_EXISTS.toString().replaceAll("%conquest%", args.getArg(0)));
+ } else {
+ conquest = new Conquest(args.getArg(0));
+ Conquest.getConquests().put(conquest.getName(), conquest);
+ ConquestFaction faction = new ConquestFaction(null, conquest.getName(), conquest);
+ conquest.setFaction(faction);
+ Faction.getFactions().put(faction.getUuid().toString(), faction);
+ HCF.getInstance().getBackend().createConquest(conquest);
+ HCF.getInstance().getBackend().createFaction(faction);
+ p.sendMessage(Locale.COMMAND_CONQUEST_CREATED.toString().replaceAll("%conquest%", conquest.getName()));
+ }
+ return;
+ }
+
+ if(Conquest.getConquest(args.getArg(0)) == null) {
+ p.sendMessage(Locale.COMMAND_CONQUEST_DOESNT_EXIST.toString().replaceAll("%conquest%", args.getArg(0)));
+ p.sendMessage(Locale.COMMAND_CONQUEST_DOESNT_EXIST_SUBTEXT.toString().replaceAll("%conquest%", args.getArg(0)));
+ return;
+ }
+
+ conquest = Conquest.getConquest(args.getArg(0));
+
+ switch(args.getArg(1).toLowerCase()) {
+ case "delete":
+ conquest.stop();
+ ConquestFaction faction = conquest.getFaction();
+ if(faction != null) {
+ faction.removeClaims();
+ HCF.getInstance().getBackend().deleteFaction(conquest.getFaction());
+ Faction.getFactions().remove(faction.getUuid().toString());
+ }
+
+ HCF.getInstance().getBackend().deleteConquest(conquest);
+ Conquest.getConquests().remove(conquest.getName());
+ p.sendMessage(Locale.COMMAND_CONQUEST_DELETED.toString().replaceAll("%conquest%", conquest.getName()));
+ return;
+ case "start":
+ conquest.start();
+ return;
+ case "stop":
+ conquest.stop();
+ return;
+ case "setarea":
+ p.sendMessage(Locale.COMMAND_CONQUEST_SETAREA_USAGE.toString());
+ return;
+ case "setpoints":
+ p.sendMessage(Locale.COMMAND_CONQUEST_SETPOINTS_USAGE.toString());
+ return;
+ default:
+ this.sendUsage(p);
+ }
+ return;
+ case 3:
+ switch(args.getArg(1).toLowerCase()) {
+ case "setarea":
+ p.sendMessage(Locale.COMMAND_CONQUEST_SETAREA_USAGE.toString());
+ return;
+ case "setpoints":
+ p.sendMessage(Locale.COMMAND_CONQUEST_SETPOINTS_USAGE.toString());
+ return;
+ default:
+ this.sendUsage(p);
+ }
+ return;
+ case 4:
+ if(Conquest.getConquest(args.getArg(0)) == null) {
+ p.sendMessage(Locale.COMMAND_CONQUEST_DOESNT_EXIST.toString().replaceAll("%conquest%", args.getArg(0)));
+ p.sendMessage(Locale.COMMAND_CONQUEST_DOESNT_EXIST_SUBTEXT.toString().replaceAll("%conquest%", args.getArg(0)));
+ return;
+ }
+
+ conquest = Conquest.getConquest(args.getArg(0));
+
+ switch(args.getArg(1).toLowerCase()) {
+ case "setarea":
+ String rawPoint = args.getArg(2);
+ String rawArea = args.getArg(3);
+
+ try {
+ ConquestZoneType.valueOf(rawPoint.toUpperCase());
+ } catch(Exception ex) {
+ p.sendMessage(Locale.COMMAND_CONQUEST_SETAREA_INVALID_ZONE.toString().replaceAll("%zone%", rawPoint));
+ return;
+ }
+
+ if(ConquestZoneType.valueOf(rawPoint.toUpperCase()) != null) {
+ ConquestZoneType type = ConquestZoneType.valueOf(rawPoint.toUpperCase());
+
+ try {
+ int area = Integer.parseInt(rawArea);
+ ConquestZone zone = conquest.getZones().get(type);
+
+ if(area == 1 || area == 2) {
+ if(area == 1) {
+ zone.setCorner1(p.getLocation());
+ zone.reformCuboid();
+ p.sendMessage(Locale.COMMAND_CONQUEST_SETAREA_ONE.toString()
+ .replaceAll("%zonetype%", type.getColor() + type.toString())
+ .replaceAll("%conquest%", conquest.getName())
+ );
+ } else {
+ zone.setCorner2(p.getLocation());
+ zone.reformCuboid();
+ p.sendMessage(Locale.COMMAND_CONQUEST_SETAREA_TWO.toString()
+ .replaceAll("%zonetype%", type.getColor() + type.toString())
+ .replaceAll("%conquest%", conquest.getName())
+ );
+ }
+ conquest.save();
+ } else {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawArea));
+ }
+ } catch(NumberFormatException e) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawArea));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_CONQUEST_SETAREA_INVALID_ZONE.toString().replaceAll("%zone%", rawPoint));
+ }
+ return;
+ case "setpoints":
+ String rawFaction = args.getArg(2);
+ String rawPoints = args.getArg(3);
+
+ Faction fac = Faction.getByName(rawFaction);
+
+ if(fac != null) {
+ if(fac instanceof PlayerFaction) {
+ PlayerFaction pf = (PlayerFaction) fac;
+
+ try {
+ int points = Integer.parseInt(rawPoints);
+
+ conquest.getPoints().put(pf.getUuid().toString(), points);
+ } catch(NumberFormatException e) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", rawPoints));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_PLAYER.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ return;
+ default:
+ this.sendUsage(p);
+ }
+ return;
+ default:
+ this.sendUsage(p);
+ }
+ }
+
+ @Completer(label = "conquest")
+ public List onComplete(CommandData args) {
+ List list = new ArrayList<>();
+ if(args.length() == 1)
+ list.addAll(Conquest.getConquests().keySet());
+ if(args.length() == 2)
+ list.addAll(Arrays.asList("create", "delete", "start", "stop"));
+ return list;
+ }
+
+ private void sendUsage(CommandSender sender) {
+ sender.sendMessage(Locale.COMMAND_CONQUEST_USAGE.toString());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/conquest/data/ConquestEndReason.java b/src/main/java/me/hulipvp/hcf/game/event/conquest/data/ConquestEndReason.java
new file mode 100644
index 0000000..e093f1d
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/conquest/data/ConquestEndReason.java
@@ -0,0 +1,7 @@
+package me.hulipvp.hcf.game.event.conquest.data;
+
+public enum ConquestEndReason {
+
+ CAPTURED,
+ CANCELLED
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/conquest/data/ConquestZone.java b/src/main/java/me/hulipvp/hcf/game/event/conquest/data/ConquestZone.java
new file mode 100644
index 0000000..23bcd9a
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/conquest/data/ConquestZone.java
@@ -0,0 +1,75 @@
+package me.hulipvp.hcf.game.event.conquest.data;
+
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.game.faction.Cuboid;
+import me.hulipvp.hcf.utils.LocUtils;
+import org.bukkit.Location;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+public class ConquestZone {
+
+ @Getter @Setter private Location corner1, corner2;
+
+ @Getter private final ConquestZoneType type;
+
+ @Getter @Setter private long timer;
+ @Getter @Setter private UUID capper;
+
+ @Getter private Cuboid cuboid;
+ @Getter private List cappers;
+
+ public ConquestZone(Location corner1, Location corner2, ConquestZoneType type) {
+ this.corner1 = corner1;
+ this.corner2 = corner2;
+ this.type = type;
+ this.timer = TimeUnit.SECONDS.toMillis(ConfigValues.CONQUEST_TIME);
+ this.capper = null;
+ this.cappers = new ArrayList<>();
+ }
+
+ public void lowerTimer() {
+ this.timer -= TimeUnit.SECONDS.toMillis(1);
+ }
+
+ public void resetTimer() {
+ this.timer = TimeUnit.SECONDS.toMillis(ConfigValues.CONQUEST_TIME);
+ }
+
+ public Cuboid toCuboid() {
+ if(corner1 == null || corner2 == null)
+ return null;
+ if(cuboid == null)
+ cuboid = new Cuboid(corner1, corner2);
+
+ return cuboid;
+ }
+
+ public void reformCuboid() {
+ if(corner1 == null || corner2 == null)
+ return;
+
+ cuboid = new Cuboid(corner1, corner2);
+ }
+
+ @Override
+ public String toString() {
+ if(corner1 != null && corner2 != null)
+ return LocUtils.locationToString(corner1) + ":" + LocUtils.locationToString(corner2) + ":" + type.name() + ":";
+
+ return null;
+ }
+
+ public static ConquestZone fromString(String input) {
+ String[] info = input.split(":");
+ Location loc1 = LocUtils.stringToLocation(info[0]);
+ Location loc2 = LocUtils.stringToLocation(info[1]);
+ ConquestZoneType type = ConquestZoneType.valueOf(info[2]);
+ return new ConquestZone(loc1, loc2, type);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/conquest/data/ConquestZoneType.java b/src/main/java/me/hulipvp/hcf/game/event/conquest/data/ConquestZoneType.java
new file mode 100644
index 0000000..296a832
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/conquest/data/ConquestZoneType.java
@@ -0,0 +1,28 @@
+package me.hulipvp.hcf.game.event.conquest.data;
+
+import lombok.Getter;
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.ChatColor;
+
+public enum ConquestZoneType {
+
+ RED(ChatColor.RED),
+ YELLOW(ChatColor.YELLOW),
+ GREEN(ChatColor.DARK_GREEN),
+ BLUE(ChatColor.BLUE);
+
+ @Getter private final ChatColor color;
+
+ ConquestZoneType(ChatColor color) {
+ this.color = color;
+ }
+
+ public String getDisplay() {
+ return this.getColor() + WordUtils.capitalizeFully(this.name());
+ }
+
+ @Override
+ public String toString() {
+ return getDisplay();
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/koth/Koth.java b/src/main/java/me/hulipvp/hcf/game/event/koth/Koth.java
new file mode 100644
index 0000000..aac1466
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/koth/Koth.java
@@ -0,0 +1,120 @@
+package me.hulipvp.hcf.game.event.koth;
+
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.events.koth.KothEndEvent;
+import me.hulipvp.hcf.api.events.koth.KothStartEvent;
+import me.hulipvp.hcf.game.event.koth.data.KothEndReason;
+import me.hulipvp.hcf.game.event.koth.data.KothPoint;
+import me.hulipvp.hcf.game.event.koth.data.KothTime;
+import me.hulipvp.hcf.game.faction.type.event.KothFaction;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import org.bson.Document;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+public class Koth {
+
+ @Getter private static final Map koths = new HashMap<>();
+ @Getter @Setter private static Koth activeKoth;
+
+ @Getter private final String name;
+ @Getter @Setter private KothFaction faction;
+ @Getter @Setter private KothPoint point;
+ @Getter @Setter private KothTime time;
+ @Getter @Setter private long timer;
+ @Getter @Setter private UUID capper;
+ @Getter @Setter private boolean special;
+ @Getter private final List cappers;
+
+ public Koth(String name) {
+ this.name = name;
+ this.faction = null;
+ this.point = new KothPoint(null, null);
+ this.time = KothTime.getByMinutes(ConfigValues.KOTH_SPECIAL_TIMES.containsKey(name.toLowerCase()) ? ConfigValues.KOTH_SPECIAL_TIMES.get(name.toLowerCase()) : ConfigValues.KOTH_TIME);
+ this.timer = this.time.toMills();
+ this.capper = null;
+ this.special = false;
+ this.cappers = new ArrayList<>();
+ }
+
+ public void start() {
+ setActiveKoth(this);
+
+ KothStartEvent event = new KothStartEvent(this);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ }
+
+ public void stop() {
+ if(getActiveKoth() == this) {
+ setActiveKoth(null);
+
+ KothEndEvent event = new KothEndEvent(this, KothEndReason.CANCELLED);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ }
+ }
+
+ public boolean isCapperOnline() {
+ Player player = Bukkit.getPlayer(capper);
+
+ return player != null && player.isOnline();
+ }
+
+ public void save() {
+ HCF.getInstance().getBackend().saveKoth(this);
+ }
+
+ public void resetTimer() {
+ this.timer = this.time.toMills();
+ }
+
+ public void lowerTimer() {
+ this.timer -= TimeUnit.SECONDS.toMillis(1);
+ }
+
+ public Document toDocument() {
+ return new Document().append("name", this.getName()).append("faction", (this.getFaction() == null) ? null : this.getFaction().getUuid().toString()).append("point", this.getPoint().toString()).append("special", this.isSpecial());
+ }
+
+ public static Koth getKoth(String name) {
+ return getKoths().get(name);
+ }
+
+ public static void instate() {
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if(getActiveKoth() == null)
+ return;
+
+ HCFTablist.updateEvent();
+ if(getActiveKoth().getCapper() == null || !getActiveKoth().isCapperOnline()) {
+ getActiveKoth().setCapper(null);
+ getActiveKoth().resetTimer();
+ return;
+ }
+
+ getActiveKoth().lowerTimer();
+
+ if(getActiveKoth().getTimer() + TimeUnit.SECONDS.toMillis(1) != getActiveKoth().getTime().toMills() && TimeUnit.MILLISECONDS.toSeconds(getActiveKoth().getTimer()) % 30 == 0) {
+ Bukkit.broadcastMessage(Locale.EVENT_KOTH_CONTROLLING.toString().replaceAll("%name%", getActiveKoth().getName())
+ .replaceAll("%time%", TimeUtils.getFormatted(getActiveKoth().getTimer())));
+ }
+
+ if(getActiveKoth().getTimer() <= 20L) {
+ KothEndEvent event = new KothEndEvent(getActiveKoth(), KothEndReason.CAPTURED);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ getActiveKoth().stop();
+ }
+ }
+ }.runTaskTimerAsynchronously(HCF.getInstance(), 2L, 20L);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/koth/command/KothCommand.java b/src/main/java/me/hulipvp/hcf/game/event/koth/command/KothCommand.java
new file mode 100644
index 0000000..dfc18cf
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/koth/command/KothCommand.java
@@ -0,0 +1,170 @@
+package me.hulipvp.hcf.game.event.koth.command;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.event.koth.data.KothPoint;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.event.KothFaction;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.LocUtils;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.api.command.Completer;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class KothCommand {
+
+ @Command(label = "koth", permission = "command.koth", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ Koth koth;
+
+ switch(args.length()) {
+ case 1:
+ if(Koth.getKoth(args.getArg(0)) != null) {
+ koth = Koth.getKoth(args.getArg(0));
+
+ p.sendMessage(C.color(koth.getFaction().getColoredName() + "&7:"));
+ p.sendMessage(C.color(" &eName: &f" + koth.getName()));
+ p.sendMessage(C.color(" &eCorner #1: &f" + ((koth.getPoint().getCorner1() == null) ? "null" : LocUtils.locationToFomattedString(koth.getPoint().getCorner1()))));
+ p.sendMessage(C.color(" &eCorner #2: &f" + ((koth.getPoint().getCorner2() == null) ? "null" : LocUtils.locationToFomattedString(koth.getPoint().getCorner2()))));
+ p.sendMessage(C.color(" &eTime: &f" + koth.getTime().getMinutes() + " minutes"));
+ p.sendMessage(C.color(" &eActive: &f" + ((Koth.getActiveKoth() == koth) ? "&aTrue" : "&cFalse")));
+ p.sendMessage(C.color(" &eSpecial: &f" + ((koth.isSpecial()) ? "&aTrue" : "&cFalse")));
+ } else {
+ p.sendMessage(Locale.COMMAND_KOTH_DOESNT_EXIST.toString().replaceAll("%koth%", args.getArg(0)));
+ p.sendMessage(Locale.COMMAND_KOTH_DOESNT_EXIST_SUBTEXT.toString().replaceAll("%koth%", args.getArg(0)));
+ }
+ return;
+ case 2:
+ if(args.getArg(1).toLowerCase().equals("create")) {
+ if(Faction.getByName(args.getArg(0)) != null) {
+ p.sendMessage(Locale.COMMAND_KOTH_ALREADY_EXISTS.toString().replaceAll("%koth%", args.getArg(0)));
+ } else {
+ koth = new Koth(args.getArg(0));
+ Koth.getKoths().put(koth.getName(), koth);
+ KothFaction faction = new KothFaction(null, koth.getName(), koth);
+ koth.setFaction(faction);
+ Faction.getFactions().put(faction.getUuid().toString(), faction);
+ HCF.getInstance().getBackend().createKoth(koth);
+ HCF.getInstance().getBackend().createFaction(faction);
+ p.sendMessage(Locale.COMMAND_KOTH_CREATED.toString().replaceAll("%koth%", koth.getName()));
+ }
+ return;
+ }
+
+ if(Koth.getKoth(args.getArg(0)) == null) {
+ p.sendMessage(Locale.COMMAND_KOTH_DOESNT_EXIST.toString().replaceAll("%koth%", args.getArg(0)));
+ p.sendMessage(Locale.COMMAND_KOTH_DOESNT_EXIST_SUBTEXT.toString().replaceAll("%koth%", args.getArg(0)));
+ return;
+ }
+
+ koth = Koth.getKoth(args.getArg(0));
+ KothPoint point = koth.getPoint();
+
+ switch(args.getArg(1).toLowerCase()) {
+ case "delete":
+ koth.stop();
+ KothFaction faction = koth.getFaction();
+ if(faction != null) {
+ faction.removeClaims();
+ Faction.getFactions().remove(faction.getUuid().toString());
+ HCF.getInstance().getBackend().deleteFaction(faction);
+ }
+
+ HCF.getInstance().getBackend().deleteKoth(koth);
+ Koth.getKoths().remove(koth.getName());
+ p.sendMessage(Locale.COMMAND_KOTH_DELETED.toString().replaceAll("%koth%", koth.getName()));
+ return;
+ case "start":
+ koth.start();
+ HCFTablist.updateEvent();
+ return;
+ case "stop":
+ koth.stop();
+ HCFTablist.updateEvent();
+ return;
+ case "setpos1":
+ point.setCorner1(p.getLocation());
+ point.reformCuboid();
+ koth.setPoint(point);
+ koth.save();
+ p.sendMessage(Locale.COMMAND_KOTH_SETPOS1.toString().replaceAll("%koth%", koth.getName()));
+ return;
+ case "setpos2":
+ point.setCorner2(p.getLocation());
+ point.reformCuboid();
+ koth.setPoint(point);
+ koth.save();
+ p.sendMessage(Locale.COMMAND_KOTH_SETPOS2.toString().replaceAll("%koth%", koth.getName()));
+ return;
+ case "special":
+ p.sendMessage(Locale.COMMAND_KOTH_SPECIAL_USAGE.toString());
+ return;
+ case "settime":
+ p.sendMessage(Locale.COMMAND_KOTH_SETTIME_USAGE.toString());
+ return;
+ default:
+ this.sendUsage(p);
+ }
+ return;
+ case 3:
+ if(Koth.getKoth(args.getArg(0)) == null) {
+ p.sendMessage(Locale.COMMAND_KOTH_DOESNT_EXIST.toString().replaceAll("%koth%", args.getArg(0)));
+ p.sendMessage(Locale.COMMAND_KOTH_DOESNT_EXIST_SUBTEXT.toString().replaceAll("%koth%", args.getArg(0)));
+ return;
+ }
+
+ koth = Koth.getKoth(args.getArg(0));
+
+ switch(args.getArg(1).toLowerCase()) {
+ case "special":
+ boolean bool = Boolean.valueOf(args.getArg(2));
+ koth.setSpecial(bool);
+ koth.save();
+ return;
+ case "settime":
+ Integer time;
+
+ try {
+ time = Integer.parseInt(args.getArg(2));
+ } catch(NumberFormatException e) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", args.getArg(2)));
+ return;
+ }
+
+ koth.setTimer(TimeUnit.MINUTES.toMillis(time));
+ p.sendMessage(Locale.COMMAND_KOTH_SETTIME_SET.toString().replaceAll("%koth%", koth.getName()));
+ //HCFTablist.updateEvent();
+ return;
+ default:
+ this.sendUsage(p);
+ }
+ return;
+ default:
+ this.sendUsage(p);
+ }
+ }
+
+ @Completer(label = "koth")
+ public List onComplete(CommandData args) {
+ List list = new ArrayList<>();
+ if(args.length() == 1)
+ list.addAll(Koth.getKoths().keySet());
+ if(args.length() == 2)
+ list.addAll(Arrays.asList("create", "delete", "start", "stop", "setpos1", "setpos2", "settime"));
+ return list;
+ }
+
+ private void sendUsage(CommandSender sender) {
+ sender.sendMessage(Locale.COMMAND_KOTH_USAGE.toString());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/koth/data/KothEndReason.java b/src/main/java/me/hulipvp/hcf/game/event/koth/data/KothEndReason.java
new file mode 100644
index 0000000..6083a6b
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/koth/data/KothEndReason.java
@@ -0,0 +1,7 @@
+package me.hulipvp.hcf.game.event.koth.data;
+
+public enum KothEndReason {
+
+ CAPTURED,
+ CANCELLED
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/koth/data/KothPoint.java b/src/main/java/me/hulipvp/hcf/game/event/koth/data/KothPoint.java
new file mode 100644
index 0000000..96d3f01
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/koth/data/KothPoint.java
@@ -0,0 +1,50 @@
+package me.hulipvp.hcf.game.event.koth.data;
+
+import me.hulipvp.hcf.game.faction.Cuboid;
+import me.hulipvp.hcf.utils.LocUtils;
+import lombok.Getter;
+import lombok.Setter;
+import org.bukkit.Location;
+
+public class KothPoint {
+
+ @Getter @Setter private Location corner1, corner2;
+
+ @Getter private Cuboid cuboid;
+
+ public KothPoint(Location corner1, Location corner2) {
+ this.corner1 = corner1;
+ this.corner2 = corner2;
+ }
+
+ public Cuboid toCuboid() {
+ if(corner1 == null || corner2 == null)
+ return null;
+ if(cuboid == null)
+ cuboid = new Cuboid(corner1, corner2);
+
+ return cuboid;
+ }
+
+ public void reformCuboid() {
+ if(corner1 == null || corner2 == null)
+ return;
+
+ cuboid = new Cuboid(corner1, corner2);
+ }
+
+ @Override
+ public String toString() {
+ if(corner1 != null && corner2 != null)
+ return LocUtils.locationToString(corner1) + ":" + LocUtils.locationToString(corner2) + ":";
+
+ return null;
+ }
+
+ public static KothPoint fromString(String input) {
+ String[] info = input.split(":");
+ Location loc1 = LocUtils.stringToLocation(info[0]);
+ Location loc2 = LocUtils.stringToLocation(info[1]);
+ return new KothPoint(loc1, loc2);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/koth/data/KothTime.java b/src/main/java/me/hulipvp/hcf/game/event/koth/data/KothTime.java
new file mode 100644
index 0000000..ef498f8
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/koth/data/KothTime.java
@@ -0,0 +1,34 @@
+package me.hulipvp.hcf.game.event.koth.data;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+public enum KothTime {
+
+ ONE(1),
+ FIVE(5),
+ TEN(10),
+ FIFTEEN(15),
+ TWENTY(20),
+ TWENTY_FIVE(25),
+ THIRTY(30);
+
+ @Getter private final long minutes;
+
+ KothTime(long minutes) {
+ this.minutes = minutes;
+ }
+
+ public long toMills() {
+ return TimeUnit.MINUTES.toMillis(this.getMinutes());
+ }
+
+ public static KothTime getByMinutes(int minutes) {
+ return Arrays.stream(values())
+ .filter(time -> time.getMinutes() == minutes)
+ .findFirst()
+ .orElse(FIFTEEN);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/mountain/Mountain.java b/src/main/java/me/hulipvp/hcf/game/event/mountain/Mountain.java
new file mode 100644
index 0000000..0615c44
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/mountain/Mountain.java
@@ -0,0 +1,112 @@
+package me.hulipvp.hcf.game.event.mountain;
+
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.utils.*;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.events.mountain.MountainResetEvent;
+import me.hulipvp.hcf.game.event.mountain.type.MountainType;
+import me.hulipvp.hcf.game.faction.type.event.MountainFaction;
+import me.hulipvp.hcf.game.faction.Cuboid;
+import org.apache.commons.lang.WordUtils;
+import org.bson.Document;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class Mountain {
+
+ @Getter private static final Map mountains = new HashMap<>();
+
+ @Getter private final String name;
+ @Getter private final MountainType type;
+
+ @Getter @Setter private MountainFaction faction;
+ @Getter @Setter private Long lastReset;
+ @Getter @Setter private Integer resetTime;
+ @Getter @Setter private Location point1, point2;
+
+ public Mountain(String name, MountainType type) {
+ this.name = name;
+ this.type = type;
+ this.lastReset = System.currentTimeMillis();
+ this.resetTime = ConfigValues.MOUNTIAN_RESET_TIME;
+ }
+
+ public static Mountain getMountain(MountainType type) {
+ return mountains.values().stream()
+ .filter(mountain -> mountain.getType() == type)
+ .findFirst()
+ .orElse(null);
+ }
+
+ public static Mountain getMountain(String name) {
+ return mountains.get(name);
+ }
+
+ public void save() {
+ HCF.getInstance().getBackend().saveMountain(this);
+ }
+
+ public Document toDocument() {
+ Document doc = new Document();
+
+ doc.append("name", this.getName());
+ doc.append("type", this.getType().name());
+ doc.append("resetTime", this.getResetTime());
+
+ if(this.getPoint1() != null)
+ doc.append("point1", LocUtils.locationToString(this.getPoint1()));
+
+ if(this.getPoint2() != null)
+ doc.append("point2", LocUtils.locationToString(this.getPoint2()));
+
+ return doc;
+ }
+
+ public void reset() {
+ if(this.getPoint1() == null || this.getPoint2() == null)
+ return;
+
+ Cuboid cuboid = new Cuboid(this.getPoint1(), this.getPoint2());
+ MountainType type = this.getType();
+
+ TaskUtils.runSync(() -> {
+ for(Block block : cuboid) {
+ switch(this.getType()) {
+ case ORE:
+ block.setType(this.getType().getMaterials()[TimeUtils.random.nextInt(type.getMaterials().length)]);
+ break;
+ case GLOWSTONE:
+ block.setType(Material.GLOWSTONE);
+ break;
+ }
+ }
+ });
+
+ this.setLastReset(System.currentTimeMillis());
+
+ MountainResetEvent event = new MountainResetEvent(this, this.lastReset);
+ Bukkit.getPluginManager().callEvent(event);
+
+ Bukkit.broadcastMessage(Locale.MOUNTAIN_RESET.toString().replaceAll("%type%", WordUtils.capitalizeFully(type.name())));
+ }
+
+ public static void instate() {
+ Bukkit.getScheduler().runTaskTimerAsynchronously(HCF.getInstance(), () -> {
+ for(Mountain mountain : Mountain.getMountains().values()) {
+ if(TimeUnit.MILLISECONDS.toMinutes(System.currentTimeMillis() - mountain.getLastReset()) >= mountain.getResetTime())
+ mountain.reset();
+ }
+ }, 100L, 20L);
+
+ Bukkit.getScheduler().runTaskLaterAsynchronously(HCF.getInstance(), () -> {
+ Mountain.getMountains().values().forEach(Mountain::reset);
+ }, 1000L);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/mountain/command/MountainCommand.java b/src/main/java/me/hulipvp/hcf/game/event/mountain/command/MountainCommand.java
new file mode 100644
index 0000000..4144d91
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/mountain/command/MountainCommand.java
@@ -0,0 +1,136 @@
+package me.hulipvp.hcf.game.event.mountain.command;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import me.hulipvp.hcf.game.event.mountain.type.MountainType;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.event.ConquestFaction;
+import me.hulipvp.hcf.game.faction.type.event.MountainFaction;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class MountainCommand {
+
+ @Command(label = "mountain", permission = "command.mountain", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player player = (Player) args.getSender();
+ Mountain mountain;
+
+ switch(args.length()) {
+ case 1:
+ if(Mountain.getMountain(args.getArg(0)) != null)
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_EXISTS.toString());
+ else
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_USAGE.toString());
+ return;
+ case 2:
+ if(args.getArg(1).equalsIgnoreCase("create")) {
+ if(Mountain.getMountain(args.getArg(0)) != null) {
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_EXISTS.toString());
+ return;
+ }
+ }
+
+ if(Mountain.getMountain(args.getArg(0)) == null) {
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_DOESNT_EXIST.toString().replaceAll("%mountain%", args.getArg(0)));
+ return;
+ }
+
+ mountain = Mountain.getMountain(args.getArg(0));
+
+ switch(args.getArg(1).toLowerCase()) {
+ case "delete":
+ MountainFaction faction = mountain.getFaction();
+ if(faction != null) {
+ faction.removeClaims();
+ HCF.getInstance().getBackend().deleteFaction(faction);
+ Faction.getFactions().remove(faction.getUuid().toString());
+ }
+
+ HCF.getInstance().getBackend().deleteFaction(mountain.getFaction());
+ HCF.getInstance().getBackend().deleteMountain(mountain);
+ Mountain.getMountains().remove(mountain.getName());
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_REMOVED.toString().replaceAll("%mountain%", mountain.getName()));
+ return;
+ case "reset":
+ mountain.reset(); // No need to send message cuz of reset broadcast
+ return;
+ case "setpos1":
+ mountain.setPoint1(player.getLocation());
+ mountain.save();
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_SETPOS1.toString().replaceAll("%mountain%", mountain.getName()));
+ return;
+ case "setpos2":
+ mountain.setPoint2(player.getLocation());
+ mountain.save();
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_SETPOS2.toString().replaceAll("%mountain%", mountain.getName()));
+ return;
+ default:
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_USAGE.toString());
+ return;
+ }
+ case 3:
+ switch(args.getArg(1).toLowerCase()) {
+ case "create": {
+ if(Mountain.getMountain(args.getArg(0)) != null) {
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_EXISTS.toString());
+ return;
+ }
+
+ MountainType type;
+ try {
+ type = MountainType.valueOf(args.getArg(2).toUpperCase());
+ } catch(Exception ex) {
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_INVALID_TYPE.toString());
+ return;
+ }
+
+ mountain = new Mountain(args.getArg(0), type);
+ if(Faction.getByName(args.getArg(0)) != null) {
+ Faction oldFaction = Faction.getByName(args.getArg(0));
+ HCF.getInstance().getBackend().deleteFaction(oldFaction);
+ Faction.getFactions().remove(oldFaction.getUuid().toString());
+ }
+
+ MountainFaction mountainFaction = new MountainFaction(null, mountain.getName(), mountain);
+ HCF.getInstance().getBackend().createMountain(mountain);
+ HCF.getInstance().getBackend().createFaction(mountainFaction);
+
+ mountain.setFaction(mountainFaction);
+
+ Mountain.getMountains().put(mountain.getName(), mountain);
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_CREATED.toString().replaceAll("%mountain%", mountain.getName()));
+ break;
+ }
+ case "setreset": {
+ if(Mountain.getMountain(args.getArg(0)) == null) {
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_DOESNT_EXIST.toString().replaceAll("%mountain%", args.getArg(0)));
+ return;
+ }
+
+ mountain = Mountain.getMountain(args.getArg(0));
+
+ String unparsed = args.getArg(2);
+ if(!StringUtils.isInt(unparsed)) {
+ player.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", unparsed));
+ return;
+ }
+
+ Integer time = Integer.parseInt(unparsed);
+ mountain.setResetTime(time);
+ mountain.save();
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_SET_TIME.toString().replaceAll("%mountain%", mountain.getName()).replaceAll("%time%", unparsed));
+ break;
+ }
+ default:
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_USAGE.toString());
+ }
+ return;
+ default:
+ player.sendMessage(Locale.COMMAND_MOUNTAIN_USAGE.toString());
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/event/mountain/type/MountainType.java b/src/main/java/me/hulipvp/hcf/game/event/mountain/type/MountainType.java
new file mode 100644
index 0000000..de40653
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/event/mountain/type/MountainType.java
@@ -0,0 +1,22 @@
+package me.hulipvp.hcf.game.event.mountain.type;
+
+import lombok.Getter;
+import org.bukkit.Material;
+
+import java.util.Arrays;
+
+public enum MountainType {
+
+ ORE(Material.COAL_ORE, Material.IRON_ORE, Material.GOLD_ORE, Material.LAPIS_ORE, Material.REDSTONE_ORE, Material.EMERALD_ORE, Material.DIAMOND_ORE),
+ GLOWSTONE(Material.GLOWSTONE);
+
+ @Getter private final Material[] materials;
+
+ MountainType(Material... materials) {
+ this.materials = materials;
+ }
+
+ public boolean hasMaterial(Material material) {
+ return Arrays.asList(materials).contains(material);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/Claim.java b/src/main/java/me/hulipvp/hcf/game/faction/Claim.java
new file mode 100644
index 0000000..4ba674b
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/Claim.java
@@ -0,0 +1,142 @@
+package me.hulipvp.hcf.game.faction;
+
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.utils.LocUtils;
+import org.bukkit.Location;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class Claim {
+
+ @Getter private Location corner1, corner2;
+
+ @Getter @Setter private Cuboid cuboid;
+ @Getter @Setter private Faction faction;
+
+ public Claim(Location corner1, Location corner2) {
+ this.corner1 = corner1;
+ this.corner2 = corner2;
+ }
+
+ public Location getCorner3() {
+ return new Location(corner1.getWorld(), corner1.getBlockX(), 0, corner2.getBlockZ());
+ }
+
+ public Location getCorner4() {
+ return new Location(corner1.getWorld(), corner2.getBlockX(), 0, corner1.getBlockZ());
+ }
+
+ public List getCorners() {
+ return Arrays.asList(corner1, corner2, getCorner3(), getCorner4());
+ }
+
+ public Cuboid toCuboid() {
+ if(cuboid == null)
+ cuboid = new Cuboid(this.getCorner1(), this.getCorner2());
+
+ return cuboid;
+ }
+
+ public Cuboid getCuboid() {
+ return toCuboid();
+ }
+
+ @Override
+ public String toString() {
+ if(corner1 == null || corner2 == null)
+ return null;
+
+ return LocUtils.locationToString(corner1) + ":" + LocUtils.locationToString(corner2);
+ }
+
+ public static Claim fromString(String input) {
+ String[] info = input.split(":");
+ Location loc1 = LocUtils.stringToLocation(info[0]);
+ Location loc2 = LocUtils.stringToLocation(info[1]);
+ return new Claim(loc1, loc2);
+ }
+
+ public static boolean isNearby(Location loc, int buffer) {
+ for(int x = -buffer; x <= buffer; ++x) {
+ for(int z = -buffer; z <= buffer; ++z) {
+ if(x != 0 || z != 0) {
+ Faction faction = Faction.getByLocation(new Location(loc.getWorld(), loc.getBlockX() + x, loc.getBlockY(), loc.getBlockZ() + z));
+ if(faction == null)
+ continue;
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public static List getNearbyFactions(Location loc, int buffer) {
+ List nearbyFactions = new ArrayList<>();
+ for(int x = -buffer; x <= buffer; ++x) {
+ for(int z = -buffer; z <= buffer; ++z) {
+ if(x != 0 || z != 0) {
+ Faction faction = Faction.getByLocation(new Location(loc.getWorld(), loc.getBlockX() + x, loc.getBlockY(), loc.getBlockZ() + z));
+ if(faction == null)
+ continue;
+ if(nearbyFactions.contains(faction))
+ continue;
+
+ nearbyFactions.add(faction);
+ }
+ }
+ }
+
+ return nearbyFactions;
+ }
+
+ public static List getPossibleStuckLocation(Location center, int buffer) {
+ List locations = new ArrayList<>();
+ for(int x = -buffer; x <= buffer; ++x) {
+ for(int z = -buffer; z <= buffer; ++z) {
+ if(x != 0 || z != 0) {
+ Location location = new Location(center.getWorld(), center.getBlockX() + x, center.getBlockY(), center.getBlockZ() + z);
+ Faction faction = Faction.getByLocation(location);
+ if(faction != null)
+ continue;
+
+ location.add(location);
+ }
+ }
+ }
+
+ return locations;
+ }
+
+ public int getPrice() {
+ return getPrice(true);
+ }
+
+ public int getPrice(boolean selling) {
+ if(corner1 == null || corner2 == null)
+ return 0;
+ if(!corner1.getWorld().getUID().equals(corner2.getWorld().getUID()))
+ return 0;
+
+ int multiplier = 1;
+ int remaining = this.toCuboid().getVolume() / ConfigValues.FACTIONS_CLAIM_PRICE_VOLUME_DIVISOR;
+ double price = 0;
+
+ while(remaining > 0) {
+ if(--remaining % ConfigValues.FACTIONS_CLAIM_PRICE_MULTIPLIER == 0)
+ multiplier++;
+
+ price += (ConfigValues.FACTIONS_CLAIM_PRICE_PER_BLOCK * multiplier);
+ }
+
+ if(selling)
+ price *= ConfigValues.FACTIONS_CLAIM_PRICE_SELLING_MULTIPLIER;
+
+ return (int) price;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/ClaimPillar.java b/src/main/java/me/hulipvp/hcf/game/faction/ClaimPillar.java
new file mode 100644
index 0000000..e230d5e
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/ClaimPillar.java
@@ -0,0 +1,66 @@
+package me.hulipvp.hcf.game.faction;
+
+import lombok.Getter;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.utils.TaskUtils;
+import me.hulipvp.hcf.utils.TimeUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class ClaimPillar {
+
+ @Getter private static List materials = Arrays.asList(Material.WOOD, Material.GLASS, Material.STONE,
+ Material.STAINED_CLAY, Material.STAINED_GLASS, Material.ICE, Material.EMERALD_BLOCK, Material.DIAMOND_BLOCK,
+ Material.IRON_BLOCK, Material.GOLD_BLOCK, Material.SAND, Material.SANDSTONE, Material.SOUL_SAND,
+ Material.COAL_BLOCK, Material.LAPIS_BLOCK, Material.MELON_BLOCK, Material.QUARTZ_BLOCK, Material.SNOW_BLOCK,
+ Material.HAY_BLOCK, Material.NOTE_BLOCK, Material.WORKBENCH, Material.BEDROCK, Material.COBBLESTONE,
+ Material.GRAVEL, Material.DISPENSER, Material.FURNACE, Material.GRASS, Material.LEAVES, Material.LEAVES_2,
+ Material.OBSIDIAN, Material.NETHER_BRICK, Material.NETHERRACK, Material.TNT, Material.SMOOTH_BRICK, Material.PUMPKIN);
+
+ @Getter private final Location location;
+ @Getter private final Material material;
+
+ public ClaimPillar(Location location, Material material) {
+ this.location = location;
+ this.material = material;
+ }
+
+ public void display(Player claimer) {
+ TaskUtils.runSync(() -> {
+ List values = new ArrayList<>();
+ for(int i = location.getWorld().getHighestBlockYAt(location); i <= 256; i++) {
+ Location location = new Location(getLocation().getWorld(), getLocation().getBlockX(), i, getLocation().getBlockZ());
+
+ if(location.getBlock().getType() == Material.AIR) {
+ if(values.contains(location.getBlockY())) {
+ claimer.sendBlockChange(location, material, (byte) 0);
+ claimer.sendBlockChange(location.add(0.0, 2.0, 0.0), Material.GLASS, (byte) 0);
+ } else {
+ claimer.sendBlockChange(location, Material.GLASS, (byte) 0);
+ values.add(location.getBlockY() + 2);
+ }
+ }
+ }
+ });
+ }
+
+ public void remove(Player claimer) {
+ TaskUtils.runSync(() -> {
+ Location loc = new Location(location.getWorld(), location.getBlockX(), 0, location.getBlockZ());
+ for(int i = 1; i <= 256; i++) {
+ claimer.sendBlockChange(loc, loc.getBlock().getType(), loc.getBlock().getData());
+ loc.add(0, 1, 0);
+ }
+ });
+ }
+
+ public static Material getRandomMaterial() {
+ return ClaimPillar.getMaterials().get(TimeUtils.random.nextInt(getMaterials().size()));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/Cuboid.java b/src/main/java/me/hulipvp/hcf/game/faction/Cuboid.java
new file mode 100644
index 0000000..f46751b
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/Cuboid.java
@@ -0,0 +1,702 @@
+package me.hulipvp.hcf.game.faction;
+
+import lombok.Getter;
+import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.configuration.serialization.ConfigurationSerializable;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+
+public class Cuboid implements Iterable, Cloneable, ConfigurationSerializable {
+
+ private final String worldName;
+ private final int x1, y1, z1;
+ private final int x2, y2, z2;
+
+ @Getter private Location l1 = null;
+ @Getter private Location l2 = null;
+
+ /**
+ * Construct a Cuboid given two Location objects which represent any two corners of the Cuboid.
+ * Note: The 2 locations must be on the same world.
+ *
+ * @param l1 - One of the corners
+ * @param l2 - The other corner
+ */
+ public Cuboid(Location l1, Location l2) {
+ if(!l1.getWorld().equals(l2.getWorld()))
+ throw new IllegalArgumentException("Locations must be on the same world");
+
+ this.worldName = l1.getWorld().getName();
+ this.x1 = Math.min(l1.getBlockX(), l2.getBlockX());
+ this.y1 = Math.min(l1.getBlockY(), l2.getBlockY());
+ this.z1 = Math.min(l1.getBlockZ(), l2.getBlockZ());
+ this.x2 = Math.max(l1.getBlockX(), l2.getBlockX());
+ this.y2 = Math.max(l1.getBlockY(), l2.getBlockY());
+ this.z2 = Math.max(l1.getBlockZ(), l2.getBlockZ());
+ this.l1 = l1;
+ this.l2 = l2;
+ }
+
+ public boolean isInCuboid(Location location) {
+ return this.contains(location);
+ }
+
+
+ public boolean isInCuboid(Player p) {
+ return this.isInCuboid(p.getLocation());
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param other - The Cuboid to copy
+ */
+ public Cuboid(Cuboid other) {
+ this(other.getWorld().getName(), other.x1, other.y1, other.z1, other.x2, other.y2, other.z2);
+ }
+
+ /**
+ * Construct a Cuboid in the given World and xyz co-ordinates
+ *
+ * @param world - The Cuboid's world
+ * @param x1 - X co-ordinate of corner 1
+ * @param y1 - Y co-ordinate of corner 1
+ * @param z1 - Z co-ordinate of corner 1
+ * @param x2 - X co-ordinate of corner 2
+ * @param y2 - Y co-ordinate of corner 2
+ * @param z2 - Z co-ordinate of corner 2
+ */
+ public Cuboid(
+ World world,
+ int x1,
+ int y1,
+ int z1,
+ int x2,
+ int y2,
+ int z2
+ ) {
+ this.worldName = world.getName();
+ this.x1 = Math.min(x1, x2);
+ this.x2 = Math.max(x1, x2);
+ this.y1 = Math.min(y1, y2);
+ this.y2 = Math.max(y1, y2);
+ this.z1 = Math.min(z1, z2);
+ this.z2 = Math.max(z1, z2);
+ }
+
+ /**
+ * Construct a Cuboid in the given world name and xyz co-ordinates.
+ *
+ * @param worldName - The Cuboid's world name
+ * @param x1 - X co-ordinate of corner 1
+ * @param y1 - Y co-ordinate of corner 1
+ * @param z1 - Z co-ordinate of corner 1
+ * @param x2 - X co-ordinate of corner 2
+ * @param y2 - Y co-ordinate of corner 2
+ * @param z2 - Z co-ordinate of corner 2
+ */
+ private Cuboid(
+ String worldName,
+ int x1,
+ int y1,
+ int z1,
+ int x2,
+ int y2,
+ int z2
+ ) {
+ this.worldName = worldName;
+ this.x1 = Math.min(x1, x2);
+ this.x2 = Math.max(x1, x2);
+ this.y1 = Math.min(y1, y2);
+ this.y2 = Math.max(y1, y2);
+ this.z1 = Math.min(z1, z2);
+ this.z2 = Math.max(z1, z2);
+ }
+
+ /**
+ * Construct a Cuboid using a map with the following keys: worldName, x1, x2, y1, y2, z1, z2
+ *
+ * @param map - The map of keys.
+ */
+ public Cuboid(Map map) {
+ this.worldName = (String) map.get("worldName");
+ this.x1 = (Integer) map.get("x1");
+ this.x2 = (Integer) map.get("x2");
+ this.y1 = (Integer) map.get("y1");
+ this.y2 = (Integer) map.get("y2");
+ this.z1 = (Integer) map.get("z1");
+ this.z2 = (Integer) map.get("z2");
+ }
+
+ @Override
+ public Map serialize() {
+ final Map map = new HashMap<>();
+ map.put("worldName", this.worldName);
+ map.put("x1", this.x1);
+ map.put("y1", this.y1);
+ map.put("z1", this.z1);
+ map.put("x2", this.x2);
+ map.put("y2", this.y2);
+ map.put("z2", this.z2);
+ return map;
+ }
+
+ /**
+ * Get the Location of the lower northeast corner of the Cuboid (minimum XYZ co-ordinates).
+ *
+ * @return Location of the lower northeast corner
+ */
+ public Location getLowerNE() {
+ return new Location(this.getWorld(), this.x1, this.y1, this.z1);
+ }
+
+ /**
+ * Get the Location of the upper southwest corner of the Cuboid (maximum XYZ co-ordinates).
+ *
+ * @return Location of the upper southwest corner
+ */
+ public Location getUpperSW() {
+ return new Location(this.getWorld(), this.x2, this.y2, this.z2);
+ }
+
+ /**
+ * Get the blocks in the Cuboid.
+ *
+ * @return The blocks in the Cuboid
+ */
+ public List getBlocks() {
+ Iterator blockI = this.iterator();
+ List copy = new ArrayList<>();
+ while(blockI.hasNext())
+ copy.add(blockI.next());
+ return copy;
+ }
+
+ /**
+ * Get the the centre of the Cuboid.
+ *
+ * @return Location at the centre of the Cuboid
+ */
+ public Location getCenter() {
+ int x1 = this.getUpperX() + 1;
+ int y1 = this.getUpperY() + 1;
+ int z1 = this.getUpperZ() + 1;
+ return new Location(this.getWorld(), this.getLowerX() + (x1 - this.getLowerX()) / 2.0, this.getLowerY() + (y1 - this.getLowerY()) / 2.0, this.getLowerZ() + (z1 - this.getLowerZ()) / 2.0);
+ }
+
+ /**
+ * Get the Cuboid's world.
+ *
+ * @return The World object representing this Cuboid's world
+ * @throws IllegalStateException if the world is not loaded
+ */
+ public World getWorld() {
+ final World world = Bukkit.getWorld(this.worldName);
+
+ if(world == null)
+ throw new IllegalStateException("World '" + this.worldName + "' is not loaded");
+
+ return world;
+ }
+
+ /**
+ * Get the size of this Cuboid along the X axis
+ *
+ * @return Size of Cuboid along the X axis
+ */
+ public int getSizeX() {
+ return (this.x2 - this.x1) + 1;
+ }
+
+ /**
+ * Get the size of this Cuboid along the Y axis
+ *
+ * @return Size of Cuboid along the Y axis
+ */
+ public int getSizeY() {
+ return (this.y2 - this.y1) + 1;
+ }
+
+ /**
+ * Get the size of this Cuboid along the Z axis
+ *
+ * @return Size of Cuboid along the Z axis
+ */
+ public int getSizeZ() {
+ return (this.z2 - this.z1) + 1;
+ }
+
+ /**
+ * Get the minimum X co-ordinate of this Cuboid
+ *
+ * @return the minimum X co-ordinate
+ */
+ public int getLowerX() {
+ return this.x1;
+ }
+
+ /**
+ * Get the minimum Y co-ordinate of this Cuboid
+ *
+ * @return the minimum Y co-ordinate
+ */
+ public int getLowerY() {
+ return this.y1;
+ }
+
+ /**
+ * Get the minimum Z co-ordinate of this Cuboid
+ *
+ * @return the minimum Z co-ordinate
+ */
+ public int getLowerZ() {
+ return this.z1;
+ }
+
+ /**
+ * Get the maximum X co-ordinate of this Cuboid
+ *
+ * @return the maximum X co-ordinate
+ */
+ public int getUpperX() {
+ return this.x2;
+ }
+
+ /**
+ * Get the maximum Y co-ordinate of this Cuboid
+ *
+ * @return the maximum Y co-ordinate
+ */
+ public int getUpperY() {
+ return this.y2;
+ }
+
+ /**
+ * Get the maximum Z co-ordinate of this Cuboid
+ *
+ * @return the maximum Z co-ordinate
+ */
+ public int getUpperZ() {
+ return this.z2;
+ }
+
+ /**
+ * Get the Blocks at the eight corners of the Cuboid.
+ *
+ * @return array of Block objects representing the Cuboid corners
+ */
+ public Block[] corners() {
+ Block[] res = new Block[8];
+ World w = this.getWorld();
+ res[0] = w.getBlockAt(this.x1, this.y1, this.z1);
+ res[1] = w.getBlockAt(this.x1, this.y1, this.z2);
+ res[2] = w.getBlockAt(this.x1, this.y2, this.z1);
+ res[3] = w.getBlockAt(this.x1, this.y2, this.z2);
+ res[4] = w.getBlockAt(this.x2, this.y1, this.z1);
+ res[5] = w.getBlockAt(this.x2, this.y1, this.z2);
+ res[6] = w.getBlockAt(this.x2, this.y2, this.z1);
+ res[7] = w.getBlockAt(this.x2, this.y2, this.z2);
+ return res;
+ }
+
+ /**
+ * Expand the Cuboid in the given direction by the given amount. Negative amounts will shrink the Cuboid in the given direction. Shrinking a cuboid's face past the opposite face is not an error and will return a valid Cuboid.
+ *
+ * @param dir - The direction in which to expand
+ * @param amount - The number of blocks by which to expand
+ * @return A new Cuboid expanded by the given direction and amount
+ */
+ public Cuboid expand(CuboidDirection dir, int amount) {
+ switch(dir) {
+ case North:
+ return new Cuboid(this.worldName, this.x1 - amount, this.y1, this.z1, this.x2, this.y2, this.z2);
+ case South:
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2 + amount, this.y2, this.z2);
+ case East:
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1 - amount, this.x2, this.y2, this.z2);
+ case West:
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, this.z2 + amount);
+ case Down:
+ return new Cuboid(this.worldName, this.x1, this.y1 - amount, this.z1, this.x2, this.y2, this.z2);
+ case Up:
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2 + amount, this.z2);
+ default:
+ throw new IllegalArgumentException("Invalid direction " + dir);
+ }
+ }
+
+ /**
+ * Shift the Cuboid in the given direction by the given amount.
+ *
+ * @param dir - The direction in which to shift
+ * @param amount - The number of blocks by which to shift
+ * @return A new Cuboid shifted by the given direction and amount
+ */
+ public Cuboid shift(CuboidDirection dir, int amount) {
+ return expand(dir, amount).expand(dir.opposite(), -amount);
+ }
+
+ /**
+ * Outset (grow) the Cuboid in the given direction by the given amount.
+ *
+ * @param dir - The direction in which to outset (must be Horizontal, Vertical, or Both)
+ * @param amount - The number of blocks by which to outset
+ * @return A new Cuboid outset by the given direction and amount
+ */
+ public Cuboid outset(CuboidDirection dir, int amount) {
+ Cuboid c;
+ switch(dir) {
+ case Horizontal:
+ c = expand(CuboidDirection.North, amount).expand(CuboidDirection.South, amount).expand(CuboidDirection.East, amount).expand(CuboidDirection.West, amount);
+ break;
+ case Vertical:
+ c = expand(CuboidDirection.Down, amount).expand(CuboidDirection.Up, amount);
+ break;
+ case Both:
+ c = outset(CuboidDirection.Horizontal, amount).outset(CuboidDirection.Vertical, amount);
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid direction " + dir);
+ }
+ return c;
+ }
+
+ /**
+ * Inset (shrink) the Cuboid in the given direction by the given amount. Equivalent
+ * to calling outset() with a negative amount.
+ *
+ * @param dir - The direction in which to inset (must be Horizontal, Vertical, or Both)
+ * @param amount - The number of blocks by which to inset
+ * @return A new Cuboid inset by the given direction and amount
+ */
+ public Cuboid inset(CuboidDirection dir, int amount) {
+ return this.outset(dir, -amount);
+ }
+
+ /**
+ * Return true if the point at (x,y,z) is contained within this Cuboid.
+ *
+ * @param x - The X co-ordinate
+ * @param y - The Y co-ordinate
+ * @param z - The Z co-ordinate
+ * @return true if the given point is within this Cuboid, false otherwise
+ */
+ public boolean contains(int x, int y, int z) {
+ return x >= this.x1 && x <= this.x2 && y >= this.y1 && y <= this.y2 && z >= this.z1 && z <= this.z2;
+ }
+
+ /**
+ * Check if the given Block is contained within this Cuboid.
+ *
+ * @param b - The Block to check for
+ * @return true if the Block is within this Cuboid, false otherwise
+ */
+ public boolean contains(Block b) {
+ return this.contains(b.getLocation());
+ }
+
+ /**
+ * Check if the given Location is contained within this Cuboid.
+ *
+ * @param l - The Location to check for
+ * @return true if the Location is within this Cuboid, false otherwise
+ */
+ public boolean contains(Location l) {
+ if(!this.worldName.equals(l.getWorld().getName()))
+ return false;
+
+ return this.contains(l.getBlockX(), l.getBlockY(), l.getBlockZ());
+ }
+
+ /**
+ * Get the volume of this Cuboid.
+ *
+ * @return The Cuboid volume, in blocks
+ */
+ public int getVolume() {
+ return this.getSizeX() * this.getSizeY() * this.getSizeZ();
+ }
+
+ /**
+ * Get the average light level of all empty (air) blocks in the Cuboid. Returns 0 if there are no empty blocks.
+ *
+ * @return The average light level of this Cuboid
+ */
+ public byte getAverageLightLevel() {
+ long total = 0;
+ int n = 0;
+
+ for(Block b : this) {
+ if(b.isEmpty()) {
+ total += b.getLightLevel();
+ ++n;
+ }
+ }
+
+ return n > 0 ? (byte) (total / n) : 0;
+ }
+
+ /**
+ * Contract the Cuboid, returning a Cuboid with any air around the edges removed, just large enough to include all non-air blocks.
+ *
+ * @return A new Cuboid with no external air blocks
+ */
+ public Cuboid contract() {
+ return this.contract(CuboidDirection.Down).contract(CuboidDirection.South).contract(CuboidDirection.East).contract(CuboidDirection.Up).contract(CuboidDirection.North).contract(CuboidDirection.West);
+ }
+
+ /**
+ * Contract the Cuboid in the given direction, returning a new Cuboid which has no exterior empty space.
+ * E.g. A direction of Down will push the top face downwards as much as possible.
+ *
+ * @param dir - The direction in which to contract
+ * @return A new Cuboid contracted in the given direction
+ */
+ public Cuboid contract(CuboidDirection dir) {
+ Cuboid face = getFace(dir.opposite());
+
+ switch(dir) {
+ case Down:
+ while(face.containsOnly(0) && face.getLowerY() > this.getLowerY()) {
+ face = face.shift(CuboidDirection.Down, 1);
+ }
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, face.getUpperY(), this.z2);
+ case Up:
+ while(face.containsOnly(0) && face.getUpperY() < this.getUpperY()) {
+ face = face.shift(CuboidDirection.Up, 1);
+ }
+ return new Cuboid(this.worldName, this.x1, face.getLowerY(), this.z1, this.x2, this.y2, this.z2);
+ case North:
+ while(face.containsOnly(0) && face.getLowerX() > this.getLowerX()) {
+ face = face.shift(CuboidDirection.North, 1);
+ }
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1, face.getUpperX(), this.y2, this.z2);
+ case South:
+ while(face.containsOnly(0) && face.getUpperX() < this.getUpperX()) {
+ face = face.shift(CuboidDirection.South, 1);
+ }
+ return new Cuboid(this.worldName, face.getLowerX(), this.y1, this.z1, this.x2, this.y2, this.z2);
+ case East:
+ while(face.containsOnly(0) && face.getLowerZ() > this.getLowerZ()) {
+ face = face.shift(CuboidDirection.East, 1);
+ }
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, face.getUpperZ());
+ case West:
+ while(face.containsOnly(0) && face.getUpperZ() < this.getUpperZ()) {
+ face = face.shift(CuboidDirection.West, 1);
+ }
+ return new Cuboid(this.worldName, this.x1, this.y1, face.getLowerZ(), this.x2, this.y2, this.z2);
+ default:
+ throw new IllegalArgumentException("Invalid direction " + dir);
+ }
+ }
+
+ /**
+ * Get the Cuboid representing the face of this Cuboid. The resulting Cuboid will be one block thick in the axis perpendicular to the requested face.
+ *
+ * @param dir - which face of the Cuboid to get
+ * @return The Cuboid representing this Cuboid's requested face
+ */
+ public Cuboid getFace(CuboidDirection dir) {
+ switch(dir) {
+ case Down:
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y1, this.z2);
+ case Up:
+ return new Cuboid(this.worldName, this.x1, this.y2, this.z1, this.x2, this.y2, this.z2);
+ case North:
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x1, this.y2, this.z2);
+ case South:
+ return new Cuboid(this.worldName, this.x2, this.y1, this.z1, this.x2, this.y2, this.z2);
+ case East:
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z1, this.x2, this.y2, this.z1);
+ case West:
+ return new Cuboid(this.worldName, this.x1, this.y1, this.z2, this.x2, this.y2, this.z2);
+ default:
+ throw new IllegalArgumentException("Invalid direction " + dir);
+ }
+ }
+
+ /**
+ * Check if the Cuboid contains only blocks of the given type
+ *
+ * @param blockId - The block ID to check for
+ * @return true if this Cuboid contains only blocks of the given type
+ */
+ public boolean containsOnly(int blockId) {
+ for(Block b : this) {
+ if(b.getTypeId() != blockId)
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get the Cuboid big enough to hold both this Cuboid and the given one.
+ *
+ * @param other - The other cuboid.
+ * @return A new Cuboid large enough to hold this Cuboid and the given Cuboid
+ */
+ public Cuboid getBoundingCuboid(Cuboid other) {
+ if(other == null)
+ return this;
+
+ int xMin = Math.min(this.getLowerX(), other.getLowerX());
+ int yMin = Math.min(this.getLowerY(), other.getLowerY());
+ int zMin = Math.min(this.getLowerZ(), other.getLowerZ());
+ int xMax = Math.max(this.getUpperX(), other.getUpperX());
+ int yMax = Math.max(this.getUpperY(), other.getUpperY());
+ int zMax = Math.max(this.getUpperZ(), other.getUpperZ());
+
+ return new Cuboid(this.worldName, xMin, yMin, zMin, xMax, yMax, zMax);
+ }
+
+ /**
+ * Get a block relative to the lower NE point of the Cuboid.
+ *
+ * @param x - The X co-ordinate
+ * @param y - The Y co-ordinate
+ * @param z - The Z co-ordinate
+ * @return The block at the given position
+ */
+ public Block getRelativeBlock(int x, int y, int z) {
+ return this.getWorld().getBlockAt(this.x1 + x, this.y1 + y, this.z1 + z);
+ }
+
+ /**
+ * Get a block relative to the lower NE point of the Cuboid in the given World. This
+ * version of getRelativeBlock() should be used if being called many times, to avoid
+ * excessive calls to getWorld().
+ *
+ * @param w - The world
+ * @param x - The X co-ordinate
+ * @param y - The Y co-ordinate
+ * @param z - The Z co-ordinate
+ * @return The block at the given position
+ */
+ public Block getRelativeBlock(World w, int x, int y, int z) {
+ return w.getBlockAt(this.x1 + x, y1 + y, this.z1 + z);
+ }
+
+ /**
+ * Get a list of the chunks which are fully or partially contained in this cuboid.
+ *
+ * @return A list of Chunk objects
+ */
+ public List getChunks() {
+ List res = new ArrayList<>();
+
+ World w = this.getWorld();
+ int x1 = this.getLowerX() & ~0xf;
+ int x2 = this.getUpperX() & ~0xf;
+ int z1 = this.getLowerZ() & ~0xf;
+ int z2 = this.getUpperZ() & ~0xf;
+ for(int x = x1; x <= x2; x += 16) {
+ for(int z = z1; z <= z2; z += 16) {
+ res.add(w.getChunkAt(x >> 4, z >> 4));
+ }
+ }
+ return res;
+ }
+
+ public Iterator iterator() {
+ return new CuboidIterator(this.getWorld(), this.x1, this.y1, this.z1, this.x2, this.y2, this.z2);
+ }
+
+ @Override
+ public Cuboid clone() {
+ return new Cuboid(this);
+ }
+
+ @Override
+ public String toString() {
+ return "Cuboid: " + this.worldName + "," + this.x1 + "," + this.y1 + "," + this.z1 + "=>" + this.x2 + "," + this.y2 + "," + this.z2;
+ }
+
+ public class CuboidIterator implements Iterator {
+ private World w;
+ private int baseX, baseY, baseZ;
+ private int x, y, z;
+ private int sizeX, sizeY, sizeZ;
+
+ public CuboidIterator(
+ World w,
+ int x1,
+ int y1,
+ int z1,
+ int x2,
+ int y2,
+ int z2
+ ) {
+ this.w = w;
+ this.baseX = x1;
+ this.baseY = y1;
+ this.baseZ = z1;
+ this.sizeX = Math.abs(x2 - x1) + 1;
+ this.sizeY = Math.abs(y2 - y1) + 1;
+ this.sizeZ = Math.abs(z2 - z1) + 1;
+ this.x = this.y = this.z = 0;
+ }
+
+ public boolean hasNext() {
+ return this.x < this.sizeX && this.y < this.sizeY && this.z < this.sizeZ;
+ }
+
+ public Block next() {
+ Block b = this.w.getBlockAt(this.baseX + this.x, this.baseY + this.y, this.baseZ + this.z);
+ if(++x >= this.sizeX) {
+ this.x = 0;
+ if(++this.y >= this.sizeY) {
+ this.y = 0;
+ ++this.z;
+ }
+ }
+ return b;
+ }
+
+ public void remove() {
+ }
+ }
+
+ public enum CuboidDirection {
+ North,
+ East,
+ South,
+ West,
+ Up,
+ Down,
+ Horizontal,
+ Vertical,
+ Both,
+ Unknown;
+
+ public CuboidDirection opposite() {
+ switch(this) {
+ case North:
+ return South;
+ case East:
+ return West;
+ case South:
+ return North;
+ case West:
+ return East;
+ case Horizontal:
+ return Vertical;
+ case Vertical:
+ return Horizontal;
+ case Up:
+ return Down;
+ case Down:
+ return Up;
+ case Both:
+ return Both;
+ default:
+ return Unknown;
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/Faction.java b/src/main/java/me/hulipvp/hcf/game/faction/Faction.java
new file mode 100644
index 0000000..1e77c94
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/Faction.java
@@ -0,0 +1,295 @@
+package me.hulipvp.hcf.game.faction;
+
+import com.google.common.collect.HashBasedTable;
+import com.google.common.collect.Table;
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.faction.type.system.SystemFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.LocUtils;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.player.PlayerUtils;
+import me.hulipvp.hcf.utils.player.UUIDPair;
+import net.md_5.bungee.api.ChatColor;
+import org.bson.Document;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.craftbukkit.v1_7_R4.util.LongHash;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class Faction {
+
+ @Getter private static Map factions = new HashMap<>();
+
+ // Idea of storing claims inspired by iHCF
+ @Getter private static final Table claimPositions = HashBasedTable.create();
+
+ @Getter private final UUID uuid;
+ @Getter private final FactionType type;
+
+ @Getter private Set claims;
+
+ @Getter @Setter public String name;
+ @Getter @Setter private boolean deathban;
+ @Getter @Setter private Location home;
+ @Getter @Setter private long lastRename;
+
+ public Faction(UUID uuid, String name, boolean deathban, FactionType type) {
+ UUID finalUuid = UUID.randomUUID();
+ if(uuid == null)
+ while(getFaction(finalUuid) != null)
+ finalUuid = UUID.randomUUID();
+ else
+ finalUuid = uuid;
+
+ this.uuid = finalUuid;
+ this.name = name;
+ this.deathban = deathban;
+ this.type = type;
+ this.claims = new HashSet<>();
+
+ factions.put(this.uuid.toString(), this);
+ }
+
+ public String getHomeString() {
+ return (this.getHome() == null) ? null : LocUtils.locationToFomattedString(this.getHome());
+ }
+
+ public String getName() {
+ return name.replaceAll("_", " ");
+ }
+
+ public String getDisplayString() {
+ return C.color("&c" + this.getName() + " " + ((this.isDeathban()) ? me.hulipvp.hcf.utils.Locale.FACTION_DEATHBAN.toString() : Locale.FACTION_NONDEATHBAN.toString()));
+ }
+
+ public String getDisplayFor(Player player) {
+ if(this instanceof PlayerFaction) {
+ PlayerFaction pf = (PlayerFaction) this;
+ if(pf.getMembers().containsKey(player.getUniqueId()))
+ return ChatColor.GREEN + getName();
+
+ return ChatColor.RED + getName();
+ } else if(this instanceof SystemFaction) {
+ SystemFaction sf = (SystemFaction) this;
+
+ return sf.getColoredName();
+ } else {
+ return ChatColor.RED + getName();
+ }
+ }
+
+ public void addClaim(Claim claim) {
+ claim.setFaction(this);
+ claims.add(claim);
+
+ saveClaim(claim);
+ }
+
+ public void removeClaim(Claim claim) {
+ claims.remove(claim);
+ claim.setFaction(null);
+
+ deleteClaim(claim);
+ }
+
+ public void removeClaims() {
+ claims.forEach(Faction::deleteClaim);
+ claims.forEach(claim -> claim.setFaction(null));
+ claims.clear();
+ }
+
+ public void save() {
+ HCF.getInstance().getBackend().saveFaction(this);
+ }
+
+ public Document toDocument() {
+ BasicDBList claims = new BasicDBList();
+ this.claims.forEach(claim -> {
+ claims.add(new BasicDBObject().append("claim", claim.toString()));
+ });
+
+ return new Document()
+ .append("uuid", this.getUuid().toString())
+ .append("name", this.name)
+ .append("deathban", this.isDeathban())
+ .append("home", (this.getHome() == null) ? null : LocUtils.locationToString(this.getHome()))
+ .append("type", this.getType().toString())
+ .append("claims", claims);
+ }
+
+ /*=============================*/
+ // Static Methods
+
+ public static boolean isFaction(UUID uuid) {
+ return factions.containsKey(uuid.toString());
+ }
+
+ public static boolean isNotAFaction(UUID uuid) {
+ return !isFaction(uuid);
+ }
+
+ public static Faction getFaction(UUID uuid) {
+ return factions.get(uuid.toString());
+ }
+
+ public static PlayerFaction getPlayerFaction(UUID uuid) {
+ return (PlayerFaction) factions.get(uuid.toString());
+ }
+
+ public static boolean isInsideFactionTerritory(Faction faction, Location location) {
+ return !faction.getClaims().isEmpty() && faction.isInsideClaim(location);
+ }
+
+ public boolean isInsideClaim(Location location) {
+ return claims.stream()
+ .anyMatch(claim -> claim.toCuboid().isInCuboid(location));
+ }
+
+ public static void saveClaim(Claim claim) {
+ if(claimPositions.containsValue(claim))
+ return;
+
+ Cuboid cuboid = claim.toCuboid();
+ for(int x = cuboid.getLowerX(); x <= cuboid.getUpperX(); x++) {
+ for(int z = cuboid.getLowerZ(); z <= cuboid.getUpperZ(); z++)
+ claimPositions.put(cuboid.getWorld().getName(), LongHash.toLong(x, z), claim);
+ }
+ }
+
+ public static void deleteClaim(Claim claim) {
+ Cuboid cuboid = claim.toCuboid();
+ for(int x = cuboid.getLowerX(); x <= cuboid.getUpperX(); x++) {
+ for(int z = cuboid.getLowerZ(); z <= cuboid.getUpperZ(); z++)
+ claimPositions.remove(cuboid.getWorld().getName(), LongHash.toLong(x, z));
+ }
+ }
+
+ public static Claim getClaimAt(Location location) {
+ return getClaimAt(location.getWorld(), location.getBlockX(), location.getBlockZ());
+ }
+
+ public static Claim getClaimAt(World world, int x, int z) {
+ return claimPositions.get(world.getName(), LongHash.toLong(x, z));
+ }
+
+ public static Faction getByLocation(Location location) {
+ Claim claim = getClaimAt(location);
+ if(claim != null) {
+ Faction faction = claim.getFaction();
+ if(faction != null)
+ return faction;
+ }
+
+ if(LocUtils.checkWarzone(location))
+ return Faction.getByName("Warzone");
+
+ return null;
+ }
+
+ public static Faction getByName(String name) {
+ return factions.values().stream()
+ .filter(fac -> fac.name.equalsIgnoreCase(name))
+ .findFirst()
+ .orElse(null);
+ }
+
+ public static Faction getByPlayer(String name) {
+ HCFProfile profile;
+ Player player = Bukkit.getPlayerExact(name);
+ if(player != null && player.isOnline()) {
+ profile = HCFProfile.getByPlayer(player);
+ } else {
+ try {
+ UUIDPair pair = PlayerUtils.getExtraInfo(name);
+ profile = HCFProfile.getByUuid(pair.getKey());
+ } catch(Exception ex) {
+ return null;
+ }
+ }
+
+ if(profile != null && profile.hasFaction())
+ return profile.getFactionObj();
+
+ return null;
+ }
+
+ public static List findFactions(String string) {
+ if(Bukkit.isPrimaryThread())
+ return new ArrayList<>();
+
+ List factions = new ArrayList<>();
+ Faction byName = getByName(string);
+ if(byName != null)
+ factions.add(byName);
+
+ Faction byPlayer = getByPlayer(string);
+ if(byPlayer != null)
+ factions.add(byPlayer);
+
+ return factions;
+ }
+
+ public static List getAllByName(String name) {
+ return factions.values().stream()
+ .filter(fac -> fac.name.equalsIgnoreCase(name))
+ .collect(Collectors.toList());
+ }
+
+ public static void refreshSorted() {
+ /*List playerFactions = getFactions().values().stream()
+ .filter(PlayerFaction.class::isInstance)
+ .map(PlayerFaction.class::cast)
+ .filter(faction -> faction.getOnlineCount() > 0)
+ .sorted(Comparator.comparingInt(PlayerFaction::getOnlineCount))
+ .map(PlayerFaction::getUuid)
+ .collect(Collectors.toList());*/
+ List playerFactions = getFactions().values().stream()
+ .filter(PlayerFaction.class::isInstance)
+ .map(Faction::getUuid)
+ .sorted(Comparator.comparingInt(id -> {
+ UUID uuid = (UUID) id;
+ PlayerFaction faction = (PlayerFaction) getFaction(uuid);
+
+ return faction.getOnlineCount();
+ }).reversed())
+ .collect(Collectors.toList());
+ /*playerFactions.sort((id1, id2) -> {
+ PlayerFaction pf1 = (PlayerFaction) getFaction(id1), pf2 = (PlayerFaction) getFaction(id2);
+
+ return pf2.getOnlineCount() - pf1.getOnlineCount();
+ });*/
+
+ PlayerFaction.setSorted(playerFactions);
+ }
+
+ public static void instate() {
+ Bukkit.getScheduler().runTaskTimerAsynchronously(HCF.getInstance(), Faction::refreshSorted, 200L, 100L * 2); // Give some time for Factions to load
+
+ Bukkit.getScheduler().runTaskTimerAsynchronously(HCF.getInstance(), () -> {
+ Bukkit.getLogger().info("Attempting to save all factions...");
+ long start = System.currentTimeMillis();
+ Faction.getFactions().values().forEach(HCF.getInstance().getBackend()::saveFaction);
+
+ long end = System.currentTimeMillis();
+ Bukkit.getLogger().info("Saved " + Faction.getFactions().size() + " factions. Took " + (end - start) + "ms.");
+ }, 200L, (20L * 60L) * 7L); // Save 10 seconds after boot, then every 7 minutes.
+
+ Bukkit.getScheduler().runTaskTimer(HCF.getInstance(), () -> {
+ Bukkit.getWorlds().forEach(world -> {
+ world.setTime(0L);
+ });
+ }, 100L, 1000L);
+ }
+ /*=============================*/
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/FactionCommand.java b/src/main/java/me/hulipvp/hcf/game/faction/command/FactionCommand.java
new file mode 100644
index 0000000..137bd3d
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/FactionCommand.java
@@ -0,0 +1,68 @@
+package me.hulipvp.hcf.game.faction.command;
+
+import me.hulipvp.hcf.game.faction.command.args.player.all.*;
+import me.hulipvp.hcf.game.faction.command.args.player.captain.*;
+import me.hulipvp.hcf.game.faction.command.args.player.coleader.*;
+import me.hulipvp.hcf.game.faction.command.args.player.leader.*;
+import me.hulipvp.hcf.game.faction.command.args.player.member.*;
+import me.hulipvp.hcf.game.faction.command.args.staff.*;
+import lombok.Getter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FactionCommand {
+
+ @Getter private final List arguments;
+
+ public FactionCommand() {
+ this.arguments = new ArrayList<>();
+
+ this.arguments.add(new FactionAllyArgument());
+ this.arguments.add(new FactionAnnouncementArgument());
+ this.arguments.add(new FactionCaptainArgument());
+ this.arguments.add(new FactionChatArgument());
+ this.arguments.add(new FactionClaimArgument());
+ this.arguments.add(new FactionCreateArgument());
+ this.arguments.add(new FactionColeaderArugment());
+ this.arguments.add(new FactionDepositArgument());
+ this.arguments.add(new FactionDisbandArgument());
+ this.arguments.add(new FactionFocusArgument());
+ this.arguments.add(new FactionHelpArgument());
+ this.arguments.add(new FactionHomeArgument());
+ this.arguments.add(new FactionInviteArgument());
+ this.arguments.add(new FactionInvitesArgument());
+ this.arguments.add(new FactionJoinArgument());
+ this.arguments.add(new FactionKickArgument());
+ this.arguments.add(new FactionLeaderArgument());
+ this.arguments.add(new FactionLeaveArgument());
+ this.arguments.add(new FactionListArgument());
+ this.arguments.add(new FactionLivesArgument());
+ this.arguments.add(new FactionLocationCommand());
+ this.arguments.add(new FactionMapArgument());
+ this.arguments.add(new FactionOpenArgument());
+ this.arguments.add(new FactionSethomeArgument());
+ this.arguments.add(new FactionShowArgument());
+ this.arguments.add(new FactionRenameArgument());
+ this.arguments.add(new FactionReviveArgument());
+ this.arguments.add(new FactionStuckArgument());
+ this.arguments.add(new FactionSubclaimArgument());
+ this.arguments.add(new FactionUnallyArgument());
+ this.arguments.add(new FactionUnclaimArgument());
+ this.arguments.add(new FactionUninviteArgument());
+ this.arguments.add(new FactionWithdrawArgument());
+
+ this.arguments.add(new FactionBypassArgument());
+ this.arguments.add(new FactionClaimforArgument());
+ this.arguments.add(new FactionCreateSystemArgument());
+ this.arguments.add(new FactionForceDisbandArgument());
+ this.arguments.add(new FactionForceJoinArgument());
+ this.arguments.add(new FactionForceSethomeArgument());
+ this.arguments.add(new FactionResetClaimsArgument());
+ this.arguments.add(new FactionSetColorArgument());
+ this.arguments.add(new FactionSetDeathbanArgument());
+ this.arguments.add(new FactionSetDtrArgument());
+ this.arguments.add(new FactionSetRegenArgument());
+ this.arguments.add(new FactionTeleportArgument());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionChatArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionChatArgument.java
new file mode 100644
index 0000000..b9892c7
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionChatArgument.java
@@ -0,0 +1,42 @@
+package me.hulipvp.hcf.game.faction.command.args.player.all;
+
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.player.data.ChatMode;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionChatArgument {
+
+ @Command(label = "f.chat", aliases = { "f.c" }, playerOnly = true)
+ public void onCommand(CommandData args) {
+ if(args.length() < 1 || args.length() > 2)
+ return;
+
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ ChatMode mode;
+ if(args.length() <= 1)
+ mode = ChatMode.getNext(profile.getChatMode());
+ else
+ mode = ChatMode.getByString(args.getArg(1));
+
+ if(mode == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_CHAT_INVALID.toString().replace("%type%", args.getArg(1)));
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ if(pf == null && mode != ChatMode.PUBLIC) {
+ profile.setChatMode(ChatMode.PUBLIC);
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ profile.setChatMode(mode);
+ p.sendMessage(Locale.COMMAND_FACTION_CHAT_CHANGED.toString().replace("%mode%", mode.getDisplay()));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionCreateArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionCreateArgument.java
new file mode 100644
index 0000000..69727b8
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionCreateArgument.java
@@ -0,0 +1,54 @@
+package me.hulipvp.hcf.game.faction.command.args.player.all;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.events.faction.normal.FactionCreateEvent;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class FactionCreateArgument {
+
+ @Command(label = "f.create", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() == 2) {
+ if(profile.getFaction() != null) {
+ p.sendMessage(Locale.COMMAND_FACTION_ATTEMPT_CREATE.toString());
+ } else {
+ if(StringUtils.checkFactionName(args.getArg(1)) != null) {
+ p.sendMessage(StringUtils.checkFactionName(args.getArg(1)));
+ } else {
+ PlayerFaction pf = new PlayerFaction(null, args.getArg(1), p.getUniqueId());
+ Faction.getFactions().put(pf.getUuid().toString(), pf);
+ PlayerFaction.getSorted().add(pf.getUuid());
+ HCF.getInstance().getBackend().createFaction(pf);
+ profile.setFaction(pf.getUuid());
+ profile.save();
+ p.sendMessage(Locale.COMMAND_FACTION_CREATED.toString());
+ p.sendMessage(Locale.COMMAND_FACTION_CREATED_HELP.toString());
+
+ Bukkit.getServer().broadcastMessage(Locale.COMMAND_FACTION_CREATED_BC.toString()
+ .replaceAll("%faction%", pf.getName())
+ .replaceAll("%player%", p.getName())
+ );
+
+ FactionCreateEvent event = new FactionCreateEvent(pf, p);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+
+ HCFTablist.update(p);
+ }
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "create "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionHelpArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionHelpArgument.java
new file mode 100644
index 0000000..409048e
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionHelpArgument.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.game.faction.command.args.player.all;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionHelpArgument {
+
+ @Command(label = "f", aliases = {"f.help"}, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ for(String str : HCF.getInstance().getMessagesFile().getFactionHelp())
+ p.sendMessage(C.color(str.replace("%primary%", ConfigValues.SERVER_PRIMARY).replace("%secondary%", ConfigValues.SERVER_SECONDARY).replace("%servername%", ConfigValues.SERVER_NAME).replace("%servernamelower%", ConfigValues.SERVER_NAME.toLowerCase()).replace("%website%", ConfigValues.SERVER_WEBSITE).replace("%teamspeak%", ConfigValues.SERVER_TEAMSPEAK).replace("%store%", ConfigValues.SERVER_STORE)));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionJoinArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionJoinArgument.java
new file mode 100644
index 0000000..e94e2e9
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionJoinArgument.java
@@ -0,0 +1,90 @@
+package me.hulipvp.hcf.game.faction.command.args.player.all;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.TaskUtils;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+
+public class FactionJoinArgument {
+
+ @Command(label = "f.join", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() == 2) {
+ if(profile.getFaction() != null) {
+ p.sendMessage(Locale.COMMAND_FACTION_ATTEMPT_JOIN.toString());
+ } else {
+ TaskUtils.runAsync(() -> {
+ List factions = Faction.findFactions(args.getArg(1));
+ Faction faction;
+ if(factions.isEmpty() || ((faction = factions.get(0)) == null)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_INVITED.toString());
+ } else {
+ if(!(faction instanceof PlayerFaction)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_INVITED.toString());
+ } else {
+ PlayerFaction pf = (PlayerFaction) faction;
+
+ if(!pf.isOpen() && pf.isInvited(p.getUniqueId())) {
+ if(pf.getStartRegen() != null) {
+ p.sendMessage(Locale.COMMAND_FACTION_ON_FREEZE.toString());
+ } else {
+ pf.removeInvite(p.getUniqueId());
+ if(pf.getMembers().size() < ConfigValues.FACTIONS_MEMBER_MAX) {
+ pf.addMember(new FactionMember(p.getUniqueId(), FactionRank.MEMBER));
+ pf.save();
+ profile.setFaction(pf.getUuid());
+ profile.save();
+ pf.sendMessage(Locale.COMMAND_FACTION_JOINED.toString().replace("%name%", p.getName()));
+
+ if(pf.getDtr() < pf.getMaxDtr()) {
+ pf.setRegening(true);
+ pf.setupRegenTask();
+ }
+
+ pf.getOnlinePlayers().forEach(HCFTablist::update);
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_MEMBER_MAX.toString());
+ }
+ }
+ } else if(pf.isOpen()) {
+ if(pf.getMembers().size() < ConfigValues.FACTIONS_MEMBER_MAX) {
+ pf.addMember(new FactionMember(p.getUniqueId(), FactionRank.MEMBER));
+ pf.save();
+ profile.setFaction(pf.getUuid());
+ profile.save();
+ pf.sendMessage(Locale.COMMAND_FACTION_JOINED.toString().replace("%name%", p.getName()));
+
+ if(pf.getDtr() < pf.getMaxDtr()) {
+ pf.setRegening(true);
+ pf.setupRegenTask();
+ }
+
+ pf.getOnlinePlayers().forEach(HCFTablist::update);
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_MEMBER_MAX.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_INVITED.toString());
+ }
+ }
+ }
+ });
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "join "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionListArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionListArgument.java
new file mode 100644
index 0000000..d16e307
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionListArgument.java
@@ -0,0 +1,77 @@
+package me.hulipvp.hcf.game.faction.command.args.player.all;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TaskUtils;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+
+public class FactionListArgument {
+
+ @Command(label = "f.list", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ List factions = PlayerFaction.getSorted();
+ /*Map listedFactions = new TreeMap<>((id1, id2) -> {
+ PlayerFaction pf1 = (PlayerFaction) Faction.getFaction(id1), pf2 = (PlayerFaction) Faction.getFaction(id2);
+
+ return pf2.getOnlineCount() - pf1.getOnlineCount();
+ });*/
+ Map listedFactions = new HashMap<>();
+
+ int currentPage = 1;
+ if(args.length() == 2) {
+ try {
+ currentPage = Integer.parseInt(args.getArg(1));
+ } catch(NumberFormatException e) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replace("%number%", args.getArg(1)));
+ return;
+ }
+ }
+
+ int pages = (factions.size() / 10) + 1;
+ if(currentPage < 0 || currentPage > pages) {
+ p.sendMessage(Locale.COMMAND_FACTION_LIST_INVALID_PAGE.toString());
+ return;
+ }
+
+ int index = 0;
+ for(UUID pfUuid : factions)
+ listedFactions.put(pfUuid, index++);
+
+ int starting = (currentPage - 1) * 10;
+ sendList(p, currentPage, pages, starting, listedFactions);
+ }
+
+ private void sendList(Player p, int currentPage, int pages, int starting, Map facs) {
+ TaskUtils.runAsync(() -> {
+ int index = 0;
+
+ List> entries = new ArrayList<>(facs.entrySet());
+ entries.sort((entry1, entry2) -> {
+ PlayerFaction pf1 = (PlayerFaction) Faction.getFaction(entry1.getKey()), pf2 = (PlayerFaction) Faction.getFaction(entry2.getKey());
+
+ return pf2.getOnlineCount() - pf1.getOnlineCount();
+ });
+
+ p.sendMessage(C.color("&7&m----------------------------------------------------"));
+ p.sendMessage(C.color("&9Faction List &7(Page " + currentPage + "/" + pages + ")"));
+ for(Map.Entry entry : entries) {
+ if(index++ < starting || index > starting + 10)
+ continue;
+
+ PlayerFaction pf = PlayerFaction.getPlayerFaction(entry.getKey());
+ p.sendMessage(C.color("&7" + index + ". " + ChatColor.YELLOW + pf.getRelationColor(p) + pf.getName() + " &a(" + pf.getOnlineCount() + "/" + pf.getMembers().size() + ")"));
+ }
+ p.sendMessage(C.color("&7You are currently on &fPage " + currentPage + "/" + pages + "&7."));
+ p.sendMessage(C.color("&7To view other pages, use &e/f list &7."));
+ p.sendMessage(C.color("&7&m----------------------------------------------------"));
+ });
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionMapArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionMapArgument.java
new file mode 100644
index 0000000..f02de4c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionMapArgument.java
@@ -0,0 +1,31 @@
+package me.hulipvp.hcf.game.faction.command.args.player.all;
+
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionMapArgument {
+
+ @Command(label = "f.map", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getMapLocation() != null) {
+ profile.hideMap();
+ p.sendMessage(Locale.COMMAND_FACTION_MAP_HIDDEN.toString());
+ } else {
+ profile.updateMap(p.getLocation());
+ if(profile.getMapPillars() == null || profile.getMapPillars().isEmpty()) {
+ profile.setMapLocation(null);
+ p.sendMessage(C.color(Locale.COMMAND_FACTION_MAP_NONE_NEARBY.toString()));
+ return;
+ }
+
+ p.sendMessage(Locale.COMMAND_FACTION_MAP_SHOWN.toString());
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionShowArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionShowArgument.java
new file mode 100644
index 0000000..06caff4
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionShowArgument.java
@@ -0,0 +1,171 @@
+package me.hulipvp.hcf.game.faction.command.args.player.all;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.faction.type.system.SystemFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TaskUtils;
+import me.hulipvp.hcf.utils.TimeUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+import java.util.UUID;
+
+public class FactionShowArgument {
+
+ @Command(label = "f.show", aliases = { "f.f", "f.who" }, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() >= 2) {
+ UUID u = null;
+ try {
+ u = UUID.fromString(args.getArg(1));
+ } catch(Exception e) {
+ } finally {
+ if(u == null) {
+ TaskUtils.runAsync(() -> {
+ List factions = Faction.findFactions(args.getArg(1));
+ if(factions != null && !factions.isEmpty()) {
+ factions.forEach(faction -> {
+ sendInfo(p, faction, args.getArg(1));
+ });
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replace("%faction%", args.getArg(1)));
+ }
+ });
+ } else {
+ Faction faction = Faction.getFaction(u);
+ if(faction != null) {
+ sendInfo(p, Faction.getFaction(u), args.getArg(1));
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replace("%faction%", args.getArg(1)));
+ }
+ }
+ }
+ } else {
+ if(args.length() == 1) {
+ if(profile.getFaction() != null) {
+ sendInfo(p, profile.getFactionObj(), null);
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "show "));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "show "));
+ }
+ }
+ }
+
+ private void sendInfo(Player player, Faction fac, String name) {
+ if(fac == null) {
+ player.sendMessage(C.color(name == null ? Locale.COMMAND_FACTION_PROFILE_INVALID.toString() : Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replace("%name%", name)));
+ return;
+ }
+
+ TaskUtils.runAsync(() -> {
+ switch(fac.getType()) {
+ case PLAYER:
+ PlayerFaction pf = (PlayerFaction) fac;
+
+ String leader = ((Bukkit.getPlayer(pf.getLeader().getUuid()) != null) ? "&a" + Bukkit.getPlayer(pf.getLeader().getUuid()).getName() + "&e[&a" + HCFProfile.getByUuid(pf.getLeader().getUuid()).getKills().size() + "&e]" : "&7" + Bukkit.getOfflinePlayer(pf.getLeader().getUuid()).getName() + "&e[&a" + HCFProfile.getByUuid(pf.getLeader().getUuid()).getKills().size() + "&e]");
+
+ StringBuilder coleaders = new StringBuilder();
+ StringBuilder captains = new StringBuilder();
+ StringBuilder members = new StringBuilder();
+
+ for(UUID uuid : pf.getMembers().keySet()) {
+ OfflinePlayer of = Bukkit.getOfflinePlayer(uuid);
+
+ switch(pf.getMembers().get(uuid).getRank()) {
+ case COLEADER:
+ if(coleaders.length() == 0)
+ coleaders.append((of.isOnline()) ? "&a" : "&7").append(of.getName()).append("&e[&a").append(HCFProfile.getByUuid(uuid).getKills().size()).append("&e]");
+ else
+ coleaders.append("&7, ").append((of.isOnline()) ? "&a" : "&7").append(of.getName()).append("&e[&a").append(HCFProfile.getByUuid(uuid).getKills().size()).append("&e]");
+ break;
+ case CAPTAIN:
+ if(captains.length() == 0)
+ captains.append((of.isOnline()) ? "&a" : "&7").append(of.getName()).append("&e[&a").append(HCFProfile.getByUuid(uuid).getKills().size()).append("&e]");
+ else
+ captains.append("&7, ").append((of.isOnline()) ? "&a" : "&7").append(of.getName()).append("&e[&a").append(HCFProfile.getByUuid(uuid).getKills().size()).append("&e]");
+ break;
+ case MEMBER:
+ if(members.length() == 0)
+ members.append((of.isOnline()) ? "&a" : "&7").append(of.getName()).append("&e[&a").append(HCFProfile.getByUuid(uuid).getKills().size()).append("&e]");
+ else
+ members.append("&7, ").append((of.isOnline()) ? "&a" : "&7").append(of.getName()).append("&e[&a").append(HCFProfile.getByUuid(uuid).getKills().size()).append("&e]");
+ break;
+ }
+ }
+
+ for(String str : HCF.getInstance().getMessagesFile().getPlayerFactionShow()) {
+ if(str.contains("%coleaders%")) {
+ if(coleaders.length() == 0)
+ continue;
+ }
+ if(str.contains("%captains%")) {
+ if(captains.length() == 0)
+ continue;
+ }
+ if(str.contains("%members%")) {
+ if(members.length() == 0)
+ continue;
+ }
+ if(str.contains("%regen%")) {
+ if(pf.getStartRegen() == null)
+ continue;
+ }
+ if(str.contains("%lives%")) {
+ if(!pf.getMembers().containsKey(player.getUniqueId()) && !player.hasPermission("hcf.staff"))
+ continue;
+ }
+ if(str.contains("%announcement%")) {
+ if(!pf.getMembers().containsKey(player.getUniqueId()))
+ continue;
+ }
+ if(str.contains("%announcement%")) {
+ if(pf.getAnnouncement().length() == 0)
+ continue;
+ }
+ if(str.contains("%powerfac%")) {
+ if(!player.hasPermission("hcf.staff"))
+ continue;
+ }
+ if(str.contains("%open%")) {
+ if(!pf.isOpen())
+ continue;
+ }
+
+ try {
+ player.sendMessage(C.color(str.replace("%primary%", ConfigValues.SERVER_PRIMARY).replace("%secondary%", ConfigValues.SERVER_SECONDARY).replace("%servername%", ConfigValues.SERVER_NAME).replace("%servernamelower%", ConfigValues.SERVER_NAME.toLowerCase()).replace("%website%", ConfigValues.SERVER_WEBSITE).replace("%teamspeak%", ConfigValues.SERVER_TEAMSPEAK).replace("%store%", ConfigValues.SERVER_STORE)
+ .replace("%name%", pf.getName()).replace("%online%", String.valueOf(pf.getOnlineCount())).replace("%players%", String.valueOf(pf.getMembers().size())).replace("%home%", (pf.getHome() == null) ? "Not Set" : pf.getHomeString()).replace("%leader%", leader).replace("%coleaders%", ((coleaders.length() > 0) ? coleaders.toString() : "null")).replace("%captains%", ((captains.length() > 0) ? captains.toString() : "null")).replace("%members%", ((members.length() > 0) ? members.toString() : "null")).replace("%balance%", String.valueOf(pf.getBalance())).replace("%dtr%", (pf.getDtr() <= 0.00 ? ChatColor.RED : ChatColor.GREEN) + String.valueOf(pf.getDtr())).replace("%dtrsymbol%", pf.getDtrSymbol()).replace("%maxdtr%", String.valueOf(pf.getMaxDtr())).replace("%regen%", ((pf.getStartRegen() == null) ? "null" : TimeUtils.getTimeTill(pf.getStartRegen()))).replace("%lives%", String.valueOf(pf.getLives())).replace("%kothcaptures%", String.valueOf(pf.getKothCaptures()))
+ .replace("%open%", ((pf.isOpen()) ? "&aTrue" : "&cFalse")).replace("%announcement%", pf.getAnnouncement()).replace("%powerfac%", ((pf.isPowerFaction()) ? "&aTrue" : "&cFalse"))));
+ } catch(Exception ex) { }
+ }
+ return;
+ case SAFEZONE:
+ case WARZONE:
+ case KOTH:
+ case CONQUEST:
+ case ROAD:
+ case SYSTEM:
+ SystemFaction sf = (SystemFaction) fac;
+ String displayName = sf.getColoredName();
+
+ for(String str : HCF.getInstance().getMessagesFile().getSystemFactionShow())
+ player.sendMessage(C.color(str.replace("%primary%", ConfigValues.SERVER_PRIMARY).replace("%secondary%", ConfigValues.SERVER_SECONDARY).replace("%servername%", ConfigValues.SERVER_NAME).replace("%servernamelower%", ConfigValues.SERVER_NAME.toLowerCase()).replace("%website%", ConfigValues.SERVER_WEBSITE).replace("%teamspeak%", ConfigValues.SERVER_TEAMSPEAK).replace("%store%", ConfigValues.SERVER_STORE).replace("%name%", displayName).replace("%home%", (sf.getHome() == null && sf.getType() != FactionType.WARZONE) ? "Not Set" : sf.getHomeString())));
+ }
+ });
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionStuckArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionStuckArgument.java
new file mode 100644
index 0000000..ab436e5
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionStuckArgument.java
@@ -0,0 +1,28 @@
+package me.hulipvp.hcf.game.faction.command.args.player.all;
+
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimer;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimerType;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionStuckArgument {
+
+ @Command(label = "f.stuck", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getTimerByType(PlayerTimerType.STUCK) != null) {
+ p.sendMessage(Locale.TIMER_STUCK_RUNNING.toString());
+ } else {
+ PlayerTimer timer = new PlayerTimer(p, PlayerTimerType.STUCK);
+ timer.add();
+
+ profile.setStuckLocation(p.getLocation());
+ p.sendMessage(Locale.TIMER_STUCK.toString());
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionSubclaimArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionSubclaimArgument.java
new file mode 100644
index 0000000..c7a94f8
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/all/FactionSubclaimArgument.java
@@ -0,0 +1,19 @@
+package me.hulipvp.hcf.game.faction.command.args.player.all;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionSubclaimArgument {
+
+ @Command(label = "f.subclaim", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ for(String str : HCF.getInstance().getMessagesFile().getFactionSubclaiming())
+ p.sendMessage(C.color(str.replace("%primary%", ConfigValues.SERVER_PRIMARY).replace("%secondary%", ConfigValues.SERVER_SECONDARY).replace("%servername%", ConfigValues.SERVER_NAME).replace("%servernamelower%", ConfigValues.SERVER_NAME.toLowerCase()).replace("%website%", ConfigValues.SERVER_WEBSITE).replace("%teamspeak%", ConfigValues.SERVER_TEAMSPEAK).replace("%store%", ConfigValues.SERVER_STORE)));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionInviteArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionInviteArgument.java
new file mode 100644
index 0000000..633e5b3
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionInviteArgument.java
@@ -0,0 +1,76 @@
+package me.hulipvp.hcf.game.faction.command.args.player.captain;
+
+import me.hulipvp.hcf.api.chat.FancyMessage;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimer;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+
+public class FactionInviteArgument {
+
+ @Command(label = "f.invite", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ if(ServerTimer.isEotw()) {
+ p.sendMessage(Locale.COMMAND_EOTW_CANNOT.toString());
+ return;
+ }
+
+ if(args.length() == 2) {
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+ if(pf.isRaidable()) {
+ p.sendMessage(Locale.COMMAND_FACTION_RAIDABLE.toString());
+ return;
+ }
+
+ if(!(pf.getMembers().get(p.getUniqueId()).getRank().getRank() >= 2)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_CAPTAIN.toString());
+ } else {
+ OfflinePlayer target = Bukkit.getOfflinePlayer(args.getArg(1));
+ if(target.isOnline() || target.hasPlayedBefore()) {
+ if(pf.isInvited(target.getUniqueId())) {
+ p.sendMessage(Locale.COMMAND_FACTION_INVITE_ALREADY_IN.toString().replace("%name%", target.getName()));
+ return;
+ }
+
+ if(pf.getMembers().size() >= ConfigValues.FACTIONS_MEMBER_MAX) {
+ p.sendMessage(Locale.COMMAND_FACTION_INVITE_MEMBER_MAX.toString());
+ return;
+ }
+
+ pf.addInvite(target.getUniqueId());
+ pf.save();
+ pf.sendMessage(Locale.COMMAND_FACTION_INVITE_BC.toString().replace("%name%", target.getName()));
+
+ if(target.isOnline()) {
+ new FancyMessage(Locale.COMMAND_FACTION_INVITE_PM.toString()
+ .replace("%name%", p.getName())
+ .replace("%faction%", pf.getName()))
+ .tooltip("Click to join " + pf.getName() + ".")
+ .command("/f join " + pf.getName())
+ .send(target.getPlayer());
+// ((Player) target).sendMessage(Locale.COMMAND_FACTION_INVITE_PM.toString()
+// .replace("%name%", p.getName())
+// .replace("%faction%", pf.getName())
+// );
+ }
+ } else {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(1)));
+ }
+ }
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "invite "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionInvitesArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionInvitesArgument.java
new file mode 100644
index 0000000..b2a75bd
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionInvitesArgument.java
@@ -0,0 +1,37 @@
+package me.hulipvp.hcf.game.faction.command.args.player.captain;
+
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+
+public class FactionInvitesArgument {
+
+ @Command(label = "f.invites", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ if(!(pf.getMembers().get(p.getUniqueId()).isAtLeast(FactionRank.CAPTAIN))) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_CAPTAIN.toString());
+ return;
+ }
+
+ p.sendMessage(C.color("&9Invites: " + (pf.getInvited().size() == 0 ? "&cNone" : "")));
+ pf.getInvited().forEach(invitee -> {
+ OfflinePlayer player = Bukkit.getOfflinePlayer(invitee);
+ p.sendMessage(C.color(" &7- &a" + player.getName()));
+ });
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionKickArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionKickArgument.java
new file mode 100644
index 0000000..501408b
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionKickArgument.java
@@ -0,0 +1,65 @@
+package me.hulipvp.hcf.game.faction.command.args.player.captain;
+
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+
+public class FactionKickArgument {
+
+ @Command(label = "f.kick", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() == 2) {
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+
+ if(!(pf.getMembers().get(p.getUniqueId()).getRank().getRank() >= 2)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_CAPTAIN.toString());
+ } else {
+ OfflinePlayer target = Bukkit.getOfflinePlayer(args.getArg(1));
+ if(target.isOnline() || target.hasPlayedBefore()) {
+ if(pf.getMembers().containsKey(target.getUniqueId())) {
+ FactionMember member = pf.getMembers().get(target.getUniqueId());
+
+ if(member.getRank().getRank() < pf.getMembers().get(p.getUniqueId()).getRank().getRank()) {
+ pf.removeMember(target.getUniqueId());
+ HCFProfile targetProfile = HCFProfile.getByUuid(target.getUniqueId());
+ targetProfile.setFaction(null);
+ targetProfile.save();
+
+ if(pf.getDtr() > pf.getMaxDtr()) {
+ pf.setDtr(pf.getMaxDtr());
+ }
+
+ p.sendMessage(C.color("&eYou have successfully kicked &d" + target.getName()));
+ if(target.isOnline())
+ ((Player) target).sendMessage(C.color("&cYou have been kicked from your faction. D:"));
+ } else {
+ p.sendMessage(C.color("&cYou may not kick this player. (:"));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_PLAYER_NOT_IN.toString().replace("%name%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(1)));
+ }
+ }
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "kick "));
+ }
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionSethomeArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionSethomeArgument.java
new file mode 100644
index 0000000..09acdfb
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionSethomeArgument.java
@@ -0,0 +1,36 @@
+package me.hulipvp.hcf.game.faction.command.args.player.captain;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionSethomeArgument {
+
+ @Command(label = "f.sethome", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+
+ if(!(pf.getMembers().get(p.getUniqueId()).getRank().getRank() >= 2)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_CAPTAIN.toString());
+ } else {
+ if(Faction.isInsideFactionTerritory(pf, p.getLocation())) {
+ pf.setHome(p.getLocation());
+ pf.save();
+ pf.sendMessage(Locale.COMMAND_FACTION_HOME_UPDATED.toString().replace("%name%", p.getName()));
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_CANNOT_SET_HOME.toString());
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionUninviteArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionUninviteArgument.java
new file mode 100644
index 0000000..2fdbf02
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/captain/FactionUninviteArgument.java
@@ -0,0 +1,47 @@
+package me.hulipvp.hcf.game.faction.command.args.player.captain;
+
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+
+public class FactionUninviteArgument {
+
+ @Command(label = "f.uninvite", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() == 2) {
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+ if(!(pf.getMembers().get(p.getUniqueId()).isAtLeast(FactionRank.CAPTAIN))) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_CAPTAIN.toString());
+ } else {
+ OfflinePlayer target = Bukkit.getOfflinePlayer(args.getArg(1));
+ if(target.isOnline() || target.hasPlayedBefore()) {
+ if(!pf.isInvited(target.getUniqueId())) {
+ p.sendMessage(Locale.COMMAND_FACTION_UNINVITE_NOT_INVITED.toString().replace("%name%", target.getName()));
+ return;
+ }
+
+ pf.removeInvite(target.getUniqueId());
+ pf.save();
+ p.sendMessage(Locale.COMMAND_FACTION_UNINVITE_MESSAGE.toString().replace("%name%", target.getName()));
+ } else {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(1)));
+ }
+ }
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "uninvite "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionAnnouncementArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionAnnouncementArgument.java
new file mode 100644
index 0000000..471aeff
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionAnnouncementArgument.java
@@ -0,0 +1,45 @@
+package me.hulipvp.hcf.game.faction.command.args.player.coleader;
+
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import com.google.common.base.Joiner;
+import org.bukkit.entity.Player;
+
+public class FactionAnnouncementArgument {
+
+ @Command(label = "f.announcement", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() >= 2) {
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+
+ if(!(pf.getMembers().get(p.getUniqueId()).isAtLeast(FactionRank.COLEADER))) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_COLEADER.toString());
+ } else {
+ String announcement = Joiner.on(' ').join(args.getArgs()).replaceFirst("announcement", "").replaceFirst(" ", "");
+ if(announcement.equalsIgnoreCase("null")) {
+ pf.setAnnouncement("");
+ pf.sendMessage(Locale.COMMAND_FACTION_ANNOUNCEMENT_REMOVED.toString().replace("%name%", p.getName()));
+ pf.save();
+ } else {
+ pf.setAnnouncement(announcement);
+ pf.sendMessage(Locale.COMMAND_FACTION_ANNOUNCEMENT_CHANGED.toString().replace("%name%", p.getName()).replace("%announcement%", pf.getAnnouncement()));
+ pf.save();
+ }
+ }
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "announcement "));
+ }
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionCaptainArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionCaptainArgument.java
new file mode 100644
index 0000000..8a5635f
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionCaptainArgument.java
@@ -0,0 +1,156 @@
+package me.hulipvp.hcf.game.faction.command.args.player.coleader;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+
+public class FactionCaptainArgument {
+
+ @Command(label = "f.captain", aliases = { "f.officer" }, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ this.sendUsage(p);
+ }
+
+ @Command(label = "f.captain.list", aliases = { "f.officer.list" }, playerOnly = true)
+ public void onCaptainList(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ FactionMember pMember = pf.getMembers().get(p.getUniqueId());
+ if(!pMember.isAtLeast(FactionRank.COLEADER)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_COLEADER.toString());
+ return;
+ }
+
+ long captains = pf.getMembers().values().stream().filter(member -> member.getRank() == FactionRank.CAPTAIN).count();
+ p.sendMessage(C.color("&eFaction Captains: " + (captains == 0 ? "&cNone" : ""))); // TODO: ADD ALL TO LOCALE
+ if(captains == 0)
+ return;
+
+ int count = 1;
+ for(FactionMember member : pf.getMembers().values()) {
+ if(member.getRank() == FactionRank.CAPTAIN) {
+ p.sendMessage(C.color("&a" + count + ". &e" + Bukkit.getOfflinePlayer(member.getUuid()).getName()));
+ ++count;
+ }
+ }
+ }
+
+ @Command(label = "f.captain.add", aliases = { "f.officer.add" }, playerOnly = true)
+ public void onCaptainAdd(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ FactionMember pMember = pf.getMembers().get(p.getUniqueId());
+ if(!pMember.isAtLeast(FactionRank.COLEADER)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_COLEADER.toString());
+ return;
+ }
+
+ if(args.length() != 3) {
+ this.sendUsage(p);
+ } else {
+ OfflinePlayer target = Bukkit.getOfflinePlayer(args.getArg(2));
+ if(target.isOnline() || target.hasPlayedBefore()) {
+ if(pf.getMembers().containsKey(target.getUniqueId())) {
+ FactionMember member = pf.getMembers().get(target.getUniqueId());
+
+ if(member.isAtLeast(FactionRank.MEMBER)) {
+ member.setRank(FactionRank.CAPTAIN);
+
+ p.sendMessage(Locale.COMMAND_FACTION_CAPTAIN_SUCCESS.toString().replace("%player%", target.getName()));
+ if(target.isOnline())
+ ((Player) target).sendMessage(Locale.COMMAND_FACTION_CAPTAIN_PROMOTED.toString());
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_CHANGE_INVALID.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_PLAYER_NOT_IN.toString().replace("%name%", args.getArg(2)));
+ }
+ } else {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(2)));
+ }
+ }
+ }
+
+ @Command(label = "f.captain.remove", aliases = { "f.officer.remove" }, playerOnly = true)
+ public void onCaptainRemove(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ FactionMember pMember = pf.getMembers().get(p.getUniqueId());
+ if(!pMember.isAtLeast(FactionRank.COLEADER)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_COLEADER.toString());
+ return;
+ }
+
+ if(args.length() != 3) {
+ this.sendUsage(p);
+ } else {
+ OfflinePlayer target = Bukkit.getOfflinePlayer(args.getArg(2));
+ if(target.isOnline() || target.hasPlayedBefore()) {
+ if(pf.getMembers().containsKey(target.getUniqueId())) {
+ FactionMember member = pf.getMembers().get(target.getUniqueId());
+
+ if(member.getRank() == FactionRank.CAPTAIN) {
+ member.setRank(FactionRank.MEMBER);
+
+ p.sendMessage(Locale.COMMAND_FACTION_CAPTAIN_SUCCESS_DEMOTE.toString().replace("%player%", target.getName()));
+ if(target.isOnline())
+ ((Player) target).sendMessage(Locale.COMMAND_FACTION_CAPTAIN_DEMOTED.toString());
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_CHANGE_INVALID.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_PLAYER_NOT_IN.toString().replace("%name%", args.getArg(2)));
+ }
+ } else {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(2)));
+ }
+ }
+ }
+
+ private void sendUsage(Player player) {
+ for(String str : HCF.getInstance().getMessagesFile().getFactionCaptainHelp())
+ player.sendMessage(C.color(str
+ .replace("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replace("%secondary%", ConfigValues.SERVER_SECONDARY))
+ );
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionClaimArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionClaimArgument.java
new file mode 100644
index 0000000..0fef28f
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionClaimArgument.java
@@ -0,0 +1,77 @@
+package me.hulipvp.hcf.game.faction.command.args.player.coleader;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimerType;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimer;
+import me.hulipvp.hcf.utils.LocUtils;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+
+public class FactionClaimArgument {
+
+ @Command(label = "f.claim", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ if(ServerTimer.isEotw()) {
+ p.sendMessage(Locale.COMMAND_EOTW_CANNOT_CLAIM.toString());
+ return;
+ }
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ /*if(profile.hasTimer(PlayerTimerType.PVPTIMER)) {
+ p.sendMessage(Locale.TIMER_CANNOT_CLAIM.toString());
+ return;
+ }*/
+
+ PlayerFaction pf = profile.getFactionObj();
+ if(pf.isRaidable()) {
+ p.sendMessage(Locale.CLAIMING_RAIDABLE.toString());
+ return;
+ }
+
+ if(!(pf.getMembers().get(p.getUniqueId()).getRank().getRank() >= 2)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_COLEADER.toString());
+ } else {
+ if(pf.getClaims().size() >= 1) {
+ p.sendMessage(Locale.CLAIMING_ALREADY_CLAIMED.toString());
+ return;
+ }
+
+ if(profile.getClaimData().isClaiming()) {
+ if(p.getInventory().contains(LocUtils.getClaimingWand()))
+ p.getInventory().remove(LocUtils.getClaimingWand());
+
+ p.sendMessage(Locale.CLAIMING_ENDED.toString());
+ profile.getClaimData().setClaiming(false);
+ profile.getClaimData().setClaimingFaction(null);
+ profile.getClaimData().setPos1(null);
+ profile.getClaimData().setPos2(null);
+ profile.getClaimData().removePillars(p);
+ } else {
+ for(String str : HCF.getInstance().getMessagesFile().getFactionClaimingStart())
+ p.sendMessage(C.color(str));
+
+ if(!p.getInventory().contains(LocUtils.getClaimingWand())) {
+ p.getInventory().addItem(LocUtils.getClaimingWand());
+ p.sendMessage(Locale.CLAIMING_CLAIM_WAND.toString());
+ }
+
+ profile.getClaimData().setClaiming(true);
+ profile.getClaimData().setClaimingFaction(profile.getFaction());
+ profile.getClaimData().setPillars(new ArrayList<>());
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionUnclaimArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionUnclaimArgument.java
new file mode 100644
index 0000000..f872cae
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionUnclaimArgument.java
@@ -0,0 +1,50 @@
+package me.hulipvp.hcf.game.faction.command.args.player.coleader;
+
+import me.hulipvp.hcf.game.faction.Claim;
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FactionUnclaimArgument {
+
+ @Command(label = "f.unclaim", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ if(!(pf.getMembers().get(p.getUniqueId()).isAtLeast(FactionRank.CAPTAIN))) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_CAPTAIN.toString());
+ return;
+ }
+
+ for(Claim claim : pf.getClaims()) {
+ if(pf.getHome() != null && claim.toCuboid().isInCuboid(pf.getHome()))
+ pf.setHome(null);
+ }
+
+ int totalBack = pf.getClaims().stream().mapToInt(Claim::getPrice).sum();
+ profile.addToBalance(totalBack);
+ profile.save();
+
+ List claims = new ArrayList<>(pf.getClaims());
+ claims.forEach(pf::removeClaim);
+
+ pf.getClaims().clear();
+ pf.save();
+
+ pf.sendMessage(Locale.COMMAND_FACTION_UNCLAIM_BROADCAST.toString().replace("%player%", p.getName()));
+ p.sendMessage(Locale.COMMAND_FACTION_UNCLAIM_PLAYER.toString());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionWithdrawArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionWithdrawArgument.java
new file mode 100644
index 0000000..bf3d051
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/coleader/FactionWithdrawArgument.java
@@ -0,0 +1,66 @@
+package me.hulipvp.hcf.game.faction.command.args.player.coleader;
+
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionWithdrawArgument {
+
+ @Command(label = "f.withdraw", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() == 2) {
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+ if(!(pf.getMembers().get(p.getUniqueId()).getRank().getRank() >= 2)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_COLEADER.toString());
+ } else {
+ if(args.getArg(1).equalsIgnoreCase("all")) {
+ if(pf.getBalance() > 0) {
+ p.sendMessage(Locale.COMMAND_FACTION_WITHDRAW_SUCCESS.toString().replace("%amount%", String.valueOf(pf.getBalance())));
+ pf.sendMessage(Locale.COMMAND_FACTION_WITHDREW.toString().replace("%name%", p.getName()).replace("%amount%", String.valueOf(pf.getBalance())));
+
+ profile.setBalance(profile.getBalance() + pf.getBalance());
+ pf.setBalance(0);
+ pf.save();
+ profile.save();
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_WITHDRAW_CANNOT.toString());
+ }
+ } else {
+ try {
+ int amount = Integer.parseInt(args.getArg(1));
+ if(amount > 0) {
+ if(pf.getBalance() >= amount) {
+ p.sendMessage(Locale.COMMAND_FACTION_WITHDRAW_SUCCESS.toString().replace("%amount%", String.valueOf(amount)));
+ pf.sendMessage(Locale.COMMAND_FACTION_WITHDREW.toString().replace("%name%", p.getName()).replace("%amount%", String.valueOf(amount)));
+ profile.setBalance(profile.getBalance() + amount);
+ pf.setBalance(pf.getBalance() - amount);
+ pf.save();
+ profile.save();
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_CANNOT_AFFORD.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_WITHDRAW_CANNOT.toString());
+ }
+ } catch(NumberFormatException e) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replace("%number%", args.getArg(1)));
+ }
+ }
+ }
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "withdraw "));
+ }
+
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionAllyArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionAllyArgument.java
new file mode 100644
index 0000000..3a66251
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionAllyArgument.java
@@ -0,0 +1,75 @@
+package me.hulipvp.hcf.game.faction.command.args.player.leader;
+
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TaskUtils;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+
+public class FactionAllyArgument {
+
+ @Command(label = "f.ally", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = args.getPlayer();
+
+ if(args.length() < 2) {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "ally "));
+ } else {
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ PlayerFaction pf = profile.getFactionObj();
+ if(pf == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ if(!pf.getMembers().get(p.getUniqueId()).isAtLeast(FactionRank.LEADER)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ return;
+ }
+
+ TaskUtils.runAsync(() -> {
+ List factions = Faction.findFactions(args.getArg(1));
+ Faction faction;
+ if(factions.isEmpty() || (!((faction = factions.get(0)) instanceof PlayerFaction))) {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replace("%faction%", args.getArg(1)));
+ return;
+ }
+
+ PlayerFaction playerFaction = (PlayerFaction) faction;
+ if(pf.getAllies().size() > ConfigValues.FACTIONS_ALLY_MAX || playerFaction.getAllies().size() > ConfigValues.FACTIONS_ALLY_MAX) {
+ p.sendMessage(Locale.COMMAND_FACTION_ALLY_MAX.toString().replace("%faction%", pf.getAllies().size() > ConfigValues.FACTIONS_ALLY_MAX ? pf.getName() : playerFaction.getName()));
+ return;
+ }
+
+ if(pf.getUuid().equals(playerFaction.getUuid()) || pf.isAllied(playerFaction.getUuid()) || pf.isRequestedAlly(playerFaction.getUuid())) {
+ p.sendMessage(Locale.COMMAND_FACTION_ALLY_ALREADY.toString());
+ return;
+ }
+
+ if(playerFaction.isRequestedAlly(pf.getUuid())) {
+ playerFaction.removeRequestedAlly(pf.getUuid());
+ playerFaction.addAlly(pf.getUuid());
+ pf.addAlly(playerFaction.getUuid());
+ playerFaction.save();
+ pf.save();
+
+ pf.sendMessage(Locale.COMMAND_FACTION_ALLY_ACCEPTED.toString().replace("%faction%", playerFaction.getName()));
+ playerFaction.sendMessage(Locale.COMMAND_FACTION_ALLY_ACCEPTED.toString().replace("%faction%", pf.getName()));
+ return;
+ }
+
+ pf.addRequestedAlly(playerFaction.getUuid());
+ pf.save();
+ pf.sendMessage(Locale.COMMAND_FACTION_ALLY_SENT.toString().replace("%faction%", playerFaction.getName()));
+ playerFaction.sendMessage(Locale.COMMAND_FACTION_ALLY_PENDING.toString().replace("%faction%", pf.getName()));
+ });
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionColeaderArugment.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionColeaderArugment.java
new file mode 100644
index 0000000..3b2be78
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionColeaderArugment.java
@@ -0,0 +1,159 @@
+package me.hulipvp.hcf.game.faction.command.args.player.leader;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Player;
+
+public class FactionColeaderArugment {
+
+ @Command(label = "f.coleader", aliases = { "f.coleader" }, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ this.sendUsage(p);
+ }
+
+ @Command(label = "f.coleader.list", aliases = { "f.coleader.list" }, playerOnly = true)
+ public void onColeaderList(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ FactionMember pMember = pf.getMembers().get(p.getUniqueId());
+
+ if(pMember.getRank() != FactionRank.LEADER) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ return;
+ }
+
+ long coleaders = pf.getMembers().values().stream().filter(member -> member.getRank() == FactionRank.COLEADER).count();
+ p.sendMessage(C.color("&eFaction Coleaders: " + (coleaders == 0 ? "&cNone" : ""))); // TODO: ADD ALL TO LOCALE
+ if(coleaders == 0)
+ return;
+
+ int count = 1;
+ for(FactionMember member : pf.getMembers().values()) {
+ if(member.getRank() == FactionRank.COLEADER) {
+ p.sendMessage(C.color("&a" + count + ". &e" + Bukkit.getOfflinePlayer(member.getUuid()).getName()));
+ ++count;
+ }
+ }
+ }
+
+ @Command(label = "f.coleader.add", aliases = { "f.coleader.add" }, playerOnly = true)
+ public void onColeaderAdd(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ FactionMember pMember = pf.getMembers().get(p.getUniqueId());
+
+ if(pMember.getRank() != FactionRank.LEADER) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ return;
+ }
+
+ if(args.length() != 3) {
+ this.sendUsage(p);
+ } else {
+ OfflinePlayer target = Bukkit.getOfflinePlayer(args.getArg(2));
+ if(target.isOnline() || target.hasPlayedBefore()) {
+ if(pf.getMembers().containsKey(target.getUniqueId())) {
+ FactionMember member = pf.getMembers().get(target.getUniqueId());
+
+ if(member.isAtLeast(FactionRank.MEMBER)) {
+ member.setRank(FactionRank.COLEADER);
+
+ p.sendMessage(Locale.COMMAND_FACTION_COLEADER_SUCCESS.toString().replace("%player%", target.getName()));
+ if(target.isOnline())
+ ((Player) target).sendMessage(Locale.COMMAND_FACTION_COLEADER_PROMOTED.toString());
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_CHANGE_INVALID.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_PLAYER_NOT_IN.toString().replace("%name%", args.getArg(2)));
+ }
+ } else {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(2)));
+ }
+ }
+ }
+
+ @Command(label = "f.coleader.remove", aliases = { "f.coleader.remove" }, playerOnly = true)
+ public void onColeaderRemove(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ FactionMember pMember = pf.getMembers().get(p.getUniqueId());
+
+ if(pMember.getRank() != FactionRank.LEADER) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ return;
+ }
+
+ if(args.length() != 3) {
+ this.sendUsage(p);
+ } else {
+ OfflinePlayer target = Bukkit.getOfflinePlayer(args.getArg(2));
+ if(target.isOnline() || target.hasPlayedBefore()) {
+ if(pf.getMembers().containsKey(target.getUniqueId())) {
+ FactionMember member = pf.getMembers().get(target.getUniqueId());
+
+ if(member.getRank() == FactionRank.COLEADER) {
+ member.setRank(FactionRank.MEMBER);
+
+ p.sendMessage(Locale.COMMAND_FACTION_COLEADER_SUCCESS_DEMOTE.toString().replace("%player%", target.getName()));
+ if(target.isOnline())
+ ((Player) target).sendMessage(Locale.COMMAND_FACTION_COLEADER_DEMOTED.toString());
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_CHANGE_INVALID.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_PLAYER_NOT_IN.toString().replace("%name%", args.getArg(2)));
+ }
+ } else {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(2)));
+ }
+ }
+ }
+
+ private void sendUsage(Player player) {
+ for(String str : HCF.getInstance().getMessagesFile().getFactionColeaderHelp())
+ player.sendMessage(C.color(str
+ .replace("%primary%", ConfigValues.SERVER_PRIMARY)
+ .replace("%secondary%", ConfigValues.SERVER_SECONDARY))
+ );
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionDisbandArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionDisbandArgument.java
new file mode 100644
index 0000000..a0b4d50
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionDisbandArgument.java
@@ -0,0 +1,82 @@
+package me.hulipvp.hcf.game.faction.command.args.player.leader;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.events.faction.normal.FactionDisbandEvent;
+import me.hulipvp.hcf.game.faction.Claim;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimer;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FactionDisbandArgument {
+
+ @Command(label = "f.disband", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+
+ if(!(pf.getLeader().getUuid().toString().equals(p.getUniqueId().toString()))) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ } else {
+ if(ServerTimer.isEotw()) {
+ p.sendMessage(Locale.COMMAND_EOTW_CANNOT.toString());
+ return;
+ }
+ if(pf.isRaidable()) {
+ p.sendMessage(Locale.COMMAND_FACTION_RAIDABLE.toString());
+ return;
+ }
+
+ pf.sendMessage(Locale.COMMAND_FACTION_DISBAND_FBC.toString().replace("%name%", p.getName()));
+
+ FactionDisbandEvent event = new FactionDisbandEvent(pf, p);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+
+ /*Bukkit.getServer().broadcastMessage(Locale.COMMAND_FACTION_DISBAND_BC.toString()
+ .replace("%faction%", pf.getName())
+ .replace("%player%", Colors.getColorFor(p))
+ );*/
+
+ Bukkit.getServer().broadcastMessage(Locale.COMMAND_FACTION_DISBAND_BC.toString()
+ .replace("%faction%", pf.getName())
+ .replace("%player%", p.getName())
+ );
+
+ PlayerFaction.getSorted().remove(pf.getUuid());
+
+ for(FactionMember members : pf.getMembers().values()) {
+ HCFProfile mProfile = HCFProfile.getByUuid(members.getUuid());
+ mProfile.setFaction(null);
+ mProfile.save();
+
+ Player member = Bukkit.getPlayer(members.getUuid());
+ if(member != null)
+ HCFTablist.update(member);
+ }
+
+ List claims = new ArrayList<>(pf.getClaims());
+ claims.forEach(pf::removeClaim);
+
+ pf.getClaims().clear();
+
+ HCF.getInstance().getBackend().deleteFaction(pf);
+ Faction.getFactions().remove(pf.getUuid().toString());
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionLeaderArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionLeaderArgument.java
new file mode 100644
index 0000000..0b86a72
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionLeaderArgument.java
@@ -0,0 +1,79 @@
+package me.hulipvp.hcf.game.faction.command.args.player.leader;
+
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.player.PlayerUtils;
+import me.hulipvp.hcf.utils.player.UUIDPair;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.util.UUID;
+
+public class FactionLeaderArgument {
+
+ @Command(label = "f.leader", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = args.getPlayer();
+
+ if(args.length() < 2) {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "leader "));
+ } else {
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ PlayerFaction pf = profile.getFactionObj();
+ if(pf == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ if(!pf.getMembers().get(p.getUniqueId()).isAtLeast(FactionRank.LEADER)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ return;
+ }
+
+ Player target = Bukkit.getPlayerExact(args.getArg(1));
+ String targetName;
+ UUID targetUuid;
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(1));
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(1)));
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ if(!pf.getMembers().containsKey(targetUuid)) {
+ p.sendMessage(Locale.COMMAND_FACTION_PLAYER_NOT_IN.toString().replace("%name%", targetName));
+ return;
+ }
+
+ FactionMember targetMember = pf.getMembers().get(targetUuid);
+ if(targetMember.getRank() == FactionRank.LEADER) {
+ p.sendMessage(Locale.COMMAND_FACTION_LEADER_SELF.toString());
+ return;
+ }
+
+ FactionMember member = pf.getMembers().get(p.getUniqueId());
+ member.setRank(FactionRank.MEMBER);
+
+ targetMember.setRank(FactionRank.LEADER);
+ pf.setLeader(targetMember);
+ pf.save();
+
+ pf.getOnlinePlayers().forEach(HCFTablist::updateFaction);
+
+ pf.sendMessage(Locale.COMMAND_FACTION_LEADER_CHANGED.toString().replace("%name%", targetName));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionOpenArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionOpenArgument.java
new file mode 100644
index 0000000..207e7fb
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionOpenArgument.java
@@ -0,0 +1,34 @@
+package me.hulipvp.hcf.game.faction.command.args.player.leader;
+
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+public class FactionOpenArgument {
+
+ @Command(label = "f.open", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+ if(!pf.getLeader().getUuid().equals(p.getUniqueId())) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ return;
+ }
+
+ pf.setOpen(!pf.isOpen());
+ if(pf.isOpen() && !Locale.COMMAND_FACTION_OPEN.toString().isEmpty())
+ Bukkit.broadcastMessage(Locale.COMMAND_FACTION_OPEN.toString().replace("%faction%", pf.getName()));
+ else if(!pf.isOpen() && !Locale.COMMAND_FACTION_CLOSED.toString().isEmpty())
+ Bukkit.broadcastMessage(Locale.COMMAND_FACTION_CLOSED.toString().replace("%faction%", pf.getName()));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionRenameArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionRenameArgument.java
new file mode 100644
index 0000000..666c2d8
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionRenameArgument.java
@@ -0,0 +1,58 @@
+package me.hulipvp.hcf.game.faction.command.args.player.leader;
+
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.util.concurrent.TimeUnit;
+
+public class FactionRenameArgument {
+
+ @Command(label = "f.rename", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() == 2) {
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+ if(!pf.getMembers().get(p.getUniqueId()).isAtLeast(FactionRank.LEADER)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ return;
+ }
+
+ if(pf.getLastRename() != 0 && System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5) < pf.getLastRename()) {
+ p.sendMessage(Locale.COMMAND_FACTION_RENAME_COOLDOWN.toString());
+ return;
+ }
+
+ if(StringUtils.checkFactionName(args.getArg(1)) != null) {
+ p.sendMessage(StringUtils.checkFactionName(args.getArg(1)));
+ } else {
+ String oldName = pf.getName();
+
+ pf.setName(args.getArg(1));
+ pf.save();
+
+ pf.setLastRename(System.currentTimeMillis());
+
+ p.sendMessage(Locale.COMMAND_FACTION_RENAME.toString().replace("%name%", pf.getName()));
+ Bukkit.getServer().broadcastMessage(Locale.COMMAND_FACTION_RENAME_BROADCAST.toString().replace("%oldname%", oldName).replace("%name%", pf.getName()));
+
+ HCFTablist.update(p);
+ }
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "rename "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionReviveArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionReviveArgument.java
new file mode 100644
index 0000000..ea143db
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionReviveArgument.java
@@ -0,0 +1,81 @@
+package me.hulipvp.hcf.game.faction.command.args.player.leader;
+
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.utils.player.PlayerUtils;
+import me.hulipvp.hcf.utils.player.UUIDPair;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.util.UUID;
+
+public class FactionReviveArgument {
+
+ @Command(label = "f.revive", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = args.getPlayer();
+
+ if(args.length() != 2) {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "revive "));
+ } else {
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = profile.getFactionObj();
+ if(pf.getMembers().get(p.getUniqueId()).getRank() != FactionRank.LEADER) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ } else {
+ Player target = Bukkit.getPlayerExact(args.getArg(1));
+ String targetName;
+ UUID targetUuid;
+ HCFProfile targetProfile;
+ if(target == null) {
+ try {
+ UUIDPair uuidPair = PlayerUtils.getExtraInfo(args.getArg(1));
+ targetName = uuidPair.getValue();
+ targetUuid = uuidPair.getKey();
+ } catch(Exception ex) {
+ p.sendMessage(Locale.MOJANG_API_FAIL.toString());
+ return;
+ }
+ } else {
+ targetName = target.getName();
+ targetUuid = target.getUniqueId();
+ }
+
+ targetProfile = HCFProfile.getByUuid(targetUuid);
+ if(!pf.getMembers().containsKey(targetUuid)) {
+ p.sendMessage(Locale.COMMAND_FACTION_PLAYER_NOT_IN.toString().replace("%name%", targetName));
+ return;
+ }
+
+ int lives = pf.getLives();
+ if(lives <= 0) {
+ p.sendMessage(Locale.COMMAND_FACTION_REVIVE_NO_LIVES.toString());
+ return;
+ }
+
+ if(targetProfile.getBannedTill() != 0) {
+ if(System.currentTimeMillis() < targetProfile.getBannedTill()) {
+ targetProfile.setBannedTill(0);
+ targetProfile.save();
+
+ pf.setLives(lives - 1);
+ pf.save();
+
+ p.sendMessage(Locale.COMMAND_REVIVE_SUCCESS.toString().replace("%player%", targetName));
+ return;
+ }
+ }
+ p.sendMessage(Locale.COMMAND_REVIVE_NO_DEATHBAN.toString().replace("%player%", targetName));
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionUnallyArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionUnallyArgument.java
new file mode 100644
index 0000000..07f3243
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/leader/FactionUnallyArgument.java
@@ -0,0 +1,69 @@
+package me.hulipvp.hcf.game.faction.command.args.player.leader;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionUnallyArgument {
+
+ @Command(label = "f.unally", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = args.getPlayer();
+
+ if(args.length() < 2) {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "unally "));
+ } else {
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ PlayerFaction pf = profile.getFactionObj();
+ if(pf == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ if(!pf.getMembers().get(p.getUniqueId()).isAtLeast(FactionRank.LEADER)) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_LEADER.toString());
+ return;
+ }
+
+ Faction faction = Faction.getByName(args.getArg(1));
+ if(!(faction instanceof PlayerFaction)) {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replace("%faction%", args.getArg(1)));
+ return;
+ }
+
+ PlayerFaction playerFaction = (PlayerFaction) faction;
+ if(pf.isRequestedAlly(playerFaction.getUuid())) {
+ pf.removeRequestedAlly(playerFaction.getUuid());
+ pf.save();
+
+ p.sendMessage(Locale.COMMAND_FACTION_UNALLY_DENIED.toString().replace("%faction%", playerFaction.getName()));
+ return;
+ }
+
+ if(playerFaction.isRequestedAlly(pf.getUuid())) {
+ playerFaction.removeRequestedAlly(pf.getUuid());
+ playerFaction.save();
+
+ p.sendMessage(Locale.COMMAND_FACTION_UNALLY_REMOVED_REQUEST.toString().replace("%faction%", playerFaction.getName()));
+ return;
+ }
+
+ if(pf.isAllied(playerFaction.getUuid()) || playerFaction.isAllied(pf.getUuid())) {
+ pf.removeAlly(playerFaction.getUuid());
+ pf.save();
+ playerFaction.removeAlly(pf.getUuid());
+ playerFaction.save();
+ pf.sendMessage(Locale.COMMAND_FACTION_UNALLY_REMOVED.toString().replace("%faction%", playerFaction.getName()));
+ playerFaction.sendMessage(Locale.COMMAND_FACTION_UNALLY_REMOVED.toString().replace("%faction%", pf.getName()));
+ return;
+ }
+
+ p.sendMessage(Locale.COMMAND_FACTION_UNALLY_NOT_ALLIED.toString());
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionDepositArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionDepositArgument.java
new file mode 100644
index 0000000..a162b1f
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionDepositArgument.java
@@ -0,0 +1,68 @@
+package me.hulipvp.hcf.game.faction.command.args.player.member;
+
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionDepositArgument {
+
+ @Command(label = "f.deposit", aliases = {"f.d"}, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 2) {
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = PlayerFaction.getPlayerFaction(profile.getFaction());
+
+ if(args.getArg(1).equalsIgnoreCase("all")) {
+ if(profile.getBalance() > 0) {
+ int amount = profile.getBalance();
+ pf.setBalance(pf.getBalance() + amount);
+ profile.setBalance(0);
+ profile.save();
+ pf.save();
+
+ pf.getOnlinePlayers().forEach(HCFTablist::updateFaction);
+
+ p.sendMessage(Locale.COMMAND_FACTION_DEPOSIT_SUCCESS.toString().replace("%amount%", String.valueOf(amount)));
+ pf.sendMessage(Locale.COMMAND_FACTION_DEPOSIT.toString().replace("%name%", p.getName()).replace("%amount%", String.valueOf(amount)));
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DEPOSIT_CANNOT.toString());
+ }
+ } else {
+ try {
+ int amount = Integer.parseInt(args.getArg(1));
+ if(amount > 0) {
+ if(profile.getBalance() >= amount) {
+ p.sendMessage(Locale.COMMAND_FACTION_DEPOSIT_SUCCESS.toString().replace("%amount%", String.valueOf(amount)));
+ pf.sendMessage(Locale.COMMAND_FACTION_DEPOSIT.toString().replace("%name%", p.getName()).replace("%amount%", String.valueOf(amount)));
+ pf.setBalance(pf.getBalance() + amount);
+ profile.removeFromBalance(amount);
+ profile.save();
+ pf.save();
+
+ pf.getOnlinePlayers().forEach(HCFTablist::updateFaction);
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DEPOSIT_CANNOT_AFFORD.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DEPOSIT_CANNOT.toString());
+ }
+ } catch(NumberFormatException e) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replace("%number%", args.getArg(1)));
+ }
+ }
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "deposit "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionFocusArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionFocusArgument.java
new file mode 100644
index 0000000..5f0669c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionFocusArgument.java
@@ -0,0 +1,52 @@
+package me.hulipvp.hcf.game.faction.command.args.player.member;
+
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+public class FactionFocusArgument {
+
+ @Command(label = "f.focus", aliases = { "focus" }, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() >= 2) {
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ Player target = Bukkit.getPlayer(args.getArg(1));
+ if(target == null || !target.isOnline()) {
+ p.sendMessage(Locale.PLAYER_NOT_FOUND.toString().replace("%name%", args.getArg(1)));
+ return;
+ }
+
+ PlayerFaction pf = profile.getFactionObj();
+ if(pf.getMembers().containsKey(target.getUniqueId())) {
+ p.sendMessage(ChatColor.RED + "You cannot focus your team members.");
+ return;
+ }
+
+ if(pf.getFocused() != null) {
+ if(pf.getFocused().equals(target.getUniqueId())) {
+ pf.setFocused(null);
+ p.sendMessage(C.color("&d" + target.getName() + " &eis no longer focused."));
+ return;
+ }
+ }
+
+ pf.setFocused(target.getUniqueId());
+ pf.sendMessage(C.color("&d" + target.getName() + " &eis now focused."));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replace("%data%", "focus "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionHomeArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionHomeArgument.java
new file mode 100644
index 0000000..2472de5
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionHomeArgument.java
@@ -0,0 +1,60 @@
+package me.hulipvp.hcf.game.faction.command.args.player.member;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.faction.type.system.SafezoneFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimer;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimerType;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class FactionHomeArgument {
+
+ @Command(label = "f.home", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = PlayerFaction.getPlayerFaction(profile.getFaction());
+ if(profile.hasTimer(PlayerTimerType.COMBAT)) {
+ p.sendMessage(Locale.COMMAND_FACTION_HOME_SPAWN_TIMER.toString());
+ return;
+ }
+ if(profile.hasTimer(PlayerTimerType.PVPTIMER)) {
+ p.sendMessage(Locale.COMMAND_FACTION_HOME_PVP_TIMER.toString());
+ return;
+ }
+
+ if(pf.getHome() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_HOME_NOT_SET.toString());
+ } else {
+ List nearbyPlayers = getNearbyPlayers(p, ConfigValues.FACTIONS_INSTANT_HOME_RADIUS);
+ if(Faction.getByLocation(p.getLocation()) instanceof SafezoneFaction || nearbyPlayers.isEmpty()) {
+ p.teleport(pf.getHome());
+ p.sendMessage(Locale.FACTION_WARPING.toString().replace("%faction%", pf.getName()));
+ } else {
+ PlayerTimer timer = new PlayerTimer(p, PlayerTimerType.HOME);
+ timer.add();
+ p.sendMessage(Locale.COMMAND_FACTION_HOME_WAITING.toString());
+ }
+ }
+ }
+ }
+
+ private List getNearbyPlayers(Player player, int radius) {
+ return player.getNearbyEntities(radius, radius, radius)
+ .stream()
+ .filter(Player.class::isInstance)
+ .map(Player.class::cast)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionLeaveArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionLeaveArgument.java
new file mode 100644
index 0000000..66dad8d
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionLeaveArgument.java
@@ -0,0 +1,45 @@
+package me.hulipvp.hcf.game.faction.command.args.player.member;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionLeaveArgument {
+
+ @Command(label = "f.leave", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ if(profile.getFactionObj() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction faction = profile.getFactionObj();
+ Faction currentTerritory = Faction.getByLocation(p.getLocation());
+
+ if(faction.getLeader().getUuid().toString().equals(p.getUniqueId().toString())) {
+ p.sendMessage(C.color("&cYou cannot leave a faction you lead."));
+ return;
+ }
+
+ if(currentTerritory != null) {
+ if(currentTerritory.getName().equalsIgnoreCase(faction.getName())) {
+ p.sendMessage(C.color("&cYou must leave your faction's territory before leaving."));
+ return;
+ }
+ }
+
+ profile.setFaction(null);
+ profile.save();
+ faction.getMembers().remove(p.getUniqueId());
+ faction.save();
+ faction.sendMessage(C.color("&c" + p.getName() + " has left the faction."));
+ p.sendMessage(C.color("&eYou have left your faction."));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionLivesArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionLivesArgument.java
new file mode 100644
index 0000000..72237f8
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionLivesArgument.java
@@ -0,0 +1,53 @@
+package me.hulipvp.hcf.game.faction.command.args.player.member;
+
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionLivesArgument {
+
+ @Command(label = "f.lives", aliases = { "f.depositlives", "f.dl" }, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = args.getPlayer();
+
+ if(args.length() != 2) {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "lives "));
+ } else {
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ return;
+ }
+
+ PlayerFaction faction = profile.getFactionObj();
+ if(profile.getLives() <= 0) {
+ p.sendMessage(Locale.COMMAND_FACTION_LIVES_NO_LIVES.toString());
+ return;
+ }
+
+ if(!StringUtils.isInt(args.getArg(1))) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replace("%number%", args.getArg(1)));
+ return;
+ }
+
+ int lives = Integer.parseInt(args.getArg(1));
+ if(lives <= 0 || profile.getLives() < lives) {
+ p.sendMessage(Locale.COMMAND_FACTION_LIVES_NOT_ENOUGH.toString().replace("%amount%", args.getArg(1)));
+ return;
+ }
+
+ faction.setLives(faction.getLives() + lives);
+ faction.save();
+
+ profile.setLives(profile.getLives() - lives);
+ profile.save();
+
+ p.sendMessage(Locale.COMMAND_FACTION_LIVES_SUCCESS.toString().replace("%amount%", args.getArg(1)));
+ faction.sendExcludingMessage(p, Locale.COMMAND_FACTION_LIVES_SUCCESS_FACTION.toString().replace("%amount%", args.getArg(1)).replace("%player%", p.getName()));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionLocationCommand.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionLocationCommand.java
new file mode 100644
index 0000000..7e1d462
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/player/member/FactionLocationCommand.java
@@ -0,0 +1,38 @@
+package me.hulipvp.hcf.game.faction.command.args.player.member;
+
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.player.data.ChatMode;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+
+import java.text.DecimalFormat;
+
+public class FactionLocationCommand {
+
+ @Command(label = "f.loc", aliases = { "f.location", "tl", "telllocation", "f.tl" }, playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = args.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(profile.getFaction() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_IN.toString());
+ } else {
+ PlayerFaction pf = PlayerFaction.getPlayerFaction(profile.getFaction());
+
+ pf.sendMessage(Locale.CHAT_FORMAT_FACTION.toString().replace("%prefix%", ChatMode.FACTION.getPrefix()).replace("%name%", p.getName()).replace("%message%", getCoords(p.getLocation())));
+ }
+ }
+
+ private String getCoords(Location loc) {
+ DecimalFormat decimalFormat = TimeUtils.getREMAINING_SECONDS_TRAIL();
+ String x = decimalFormat.format(loc.getX());
+ String y = decimalFormat.format(loc.getY());
+ String z = decimalFormat.format(loc.getZ());
+ return "[" + x + ", " + y + ", " + z + "]";
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionBypassArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionBypassArgument.java
new file mode 100644
index 0000000..35cede9
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionBypassArgument.java
@@ -0,0 +1,20 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionBypassArgument {
+
+ @Command(label = "f.bypass", aliases = {"f.bypass"}, permission = "command.bypass", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ profile.setBypass(!profile.isBypass());
+
+ p.sendMessage(C.color("&eBypass mode has been " + ((profile.isBypass()) ? "&aenabled" : "&cdisabled") + "&e."));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionClaimforArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionClaimforArgument.java
new file mode 100644
index 0000000..6f54730
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionClaimforArgument.java
@@ -0,0 +1,57 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.LocUtils;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+
+public class FactionClaimforArgument {
+
+ @Command(label = "f.claimfor", aliases = {"f.cf"}, permission = "command.claimfor", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+
+ if(args.length() == 2) {
+ Faction fac = Faction.getByName(args.getArg(1));
+
+ if(fac != null) {
+ if(profile.getClaimData().isClaiming()) {
+ if(p.getInventory().contains(LocUtils.getClaimingWand()))
+ p.getInventory().remove(LocUtils.getClaimingWand());
+
+ p.sendMessage(Locale.CLAIMING_ENDED.toString());
+ profile.getClaimData().setClaiming(false);
+ profile.getClaimData().setClaimingFaction(null);
+ profile.getClaimData().setPos1(null);
+ profile.getClaimData().setPos2(null);
+ profile.getClaimData().removePillars(p);
+ } else {
+ for(String str : HCF.getInstance().getMessagesFile().getFactionClaimingStart())
+ p.sendMessage(C.color(str));
+
+ if(!p.getInventory().contains(LocUtils.getClaimingWand())) {
+ p.getInventory().addItem(LocUtils.getClaimingWand());
+ p.sendMessage(Locale.CLAIMING_CLAIM_WAND.toString());
+ }
+
+ profile.getClaimData().setClaiming(true);
+ profile.getClaimData().setClaimingFaction(fac.getUuid());
+ profile.getClaimData().setPillars(new ArrayList<>());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "claimfor "));
+ }
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionCreateSystemArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionCreateSystemArgument.java
new file mode 100644
index 0000000..ab80765
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionCreateSystemArgument.java
@@ -0,0 +1,31 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.system.SystemFaction;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionCreateSystemArgument {
+
+ @Command(label = "f.createsystem", aliases = {"f.cs"}, permission = "command.createsystem", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 2) {
+ if(StringUtils.checkFactionName(args.getArg(1)) != null) {
+ p.sendMessage(StringUtils.checkFactionName(args.getArg(1)));
+ } else {
+ SystemFaction sf = new SystemFaction(null, args.getArg(1));
+ Faction.getFactions().put(sf.getUuid().toString(), sf);
+ HCF.getInstance().getBackend().createFaction(sf);
+ p.sendMessage(Locale.COMMAND_FACTION_CREATED.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "createsystem "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceDisbandArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceDisbandArgument.java
new file mode 100644
index 0000000..a3b1566
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceDisbandArgument.java
@@ -0,0 +1,76 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.events.faction.normal.FactionDisbandEvent;
+import me.hulipvp.hcf.game.faction.Claim;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FactionForceDisbandArgument {
+
+ @Command(label = "f.forcedisband", aliases = {"f.fd"}, permission = "command.forcedisband", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 2) {
+ Faction fac = Faction.getByName(args.getArg(1));
+
+ if(fac != null) {
+ FactionDisbandEvent event = new FactionDisbandEvent(fac, p);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+
+ if(fac instanceof PlayerFaction) {
+ PlayerFaction pf = (PlayerFaction) fac;
+ pf.sendMessage(Locale.COMMAND_FACTION_DISBAND_FBC.toString().replaceAll("%name%", p.getName()));
+
+ PlayerFaction.getSorted().remove(pf.getUuid());
+
+ for(FactionMember members : pf.getMembers().values()) {
+ HCFProfile mProfile = HCFProfile.getByUuid(members.getUuid());
+ mProfile.setFaction(null);
+ mProfile.save();
+
+ Player member = Bukkit.getPlayer(members.getUuid());
+ if(member != null)
+ HCFTablist.update(member);
+ }
+ }
+
+ /*Bukkit.getServer().broadcastMessage(Locale.COMMAND_FACTION_DISBAND_BC.toString()
+ .replaceAll("%faction%", fac.getName())
+ .replaceAll("%player%", Colors.getColorFor(p))
+ );*/
+
+ Bukkit.getServer().broadcastMessage(Locale.COMMAND_FACTION_DISBAND_BC.toString()
+ .replaceAll("%faction%", fac.getName())
+ .replaceAll("%player%", p.getName())
+ );
+
+ List claims = new ArrayList<>(fac.getClaims());
+ claims.forEach(fac::removeClaim);
+
+ fac.getClaims().clear();
+
+ HCF.getInstance().getBackend().deleteFaction(fac);
+ Faction.getFactions().remove(fac.getUuid().toString());
+ Faction.refreshSorted();
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "forcedisband "));
+ }
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceJoinArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceJoinArgument.java
new file mode 100644
index 0000000..2ce4a59
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceJoinArgument.java
@@ -0,0 +1,50 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.FactionMember;
+import me.hulipvp.hcf.game.faction.type.player.FactionRank;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.entity.Player;
+
+public class FactionForceJoinArgument {
+
+ @Command(label = "f.forcejoin", aliases = { "f.fj" }, permission = "command.forcejoin", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 2) {
+ HCFProfile profile = HCFProfile.getByPlayer(p);
+ if(profile.getFaction() != null) {
+ p.sendMessage(Locale.COMMAND_FACTION_ATTEMPT_JOIN.toString());
+ return;
+ }
+
+ Faction fac = Faction.getByName(args.getArg(1));
+ if(fac != null) {
+ if(fac instanceof PlayerFaction) {
+ PlayerFaction pf = (PlayerFaction) fac;
+ if(!pf.getMembers().containsKey(p.getUniqueId()))
+ pf.addMember(new FactionMember(p.getUniqueId(), FactionRank.MEMBER));
+
+ profile.setFaction(pf.getUuid());
+ if(pf.getDtr() < pf.getMaxDtr()) {
+ pf.setRegening(true);
+ pf.setupRegenTask();
+ }
+
+ pf.sendMessage(Locale.COMMAND_FACTION_JOINED.toString().replaceAll("%name%", p.getName()));
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_PLAYER.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "forcejoin "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceLeaderArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceLeaderArgument.java
new file mode 100644
index 0000000..bf492a0
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceLeaderArgument.java
@@ -0,0 +1,4 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+public class FactionForceLeaderArgument {
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceSethomeArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceSethomeArgument.java
new file mode 100644
index 0000000..5d7ad17
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionForceSethomeArgument.java
@@ -0,0 +1,48 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionForceSethomeArgument {
+
+ @Command(label = "f.forcesethome", aliases = {"f.fsh"}, permission = "command.forcesethome", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 2) {
+ Faction faction = Faction.getByName(args.getArg(1));
+
+ if(faction != null) {
+ if(Faction.isInsideFactionTerritory(faction, p.getLocation())) {
+ faction.setHome(p.getLocation());
+ if(faction.getName().equalsIgnoreCase("Spawn"))
+ p.getWorld().setSpawnLocation(p.getLocation().getBlockX(), p.getLocation().getBlockY() + 1, p.getLocation().getBlockZ());
+
+ if(faction instanceof PlayerFaction) {
+ PlayerFaction pf = (PlayerFaction) faction;
+
+ pf.sendMessage(Locale.COMMAND_FACTION_HOME_UPDATED.toString().replaceAll("%name%", p.getName()));
+ pf.getOnlinePlayers().forEach(HCFTablist::updateFaction);
+
+ if(pf.getMembers().containsKey(p.getUniqueId()))
+ p.sendMessage(Locale.COMMAND_FACTION_HOME_UPDATED.toString().replaceAll("%name%", p.getName()));
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_HOME_UPDATED.toString().replaceAll("%name%", p.getName()));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_CANNOT_SET_HOME.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "forcesethome "));
+ }
+ }
+
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionResetClaimsArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionResetClaimsArgument.java
new file mode 100644
index 0000000..218c33d
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionResetClaimsArgument.java
@@ -0,0 +1,31 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.entity.Player;
+
+import java.util.List;
+
+public class FactionResetClaimsArgument {
+
+ @Command(label = "f.resetclaims", permission = "command.resetclaims", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() >= 2) {
+ List facs = Faction.getAllByName(args.getArg(1));
+ if(facs != null && !facs.isEmpty()) {
+ facs.forEach(Faction::removeClaims);
+ facs.forEach(Faction::save);
+
+ p.sendMessage(Locale.COMMAND_FACTION_RESET_CLAIMS.toString().replaceAll("%name%", facs.get(0).getDisplayString()));
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "resetclaims "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetColorArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetColorArgument.java
new file mode 100644
index 0000000..a50e25a
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetColorArgument.java
@@ -0,0 +1,42 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.system.SystemFaction;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+public class FactionSetColorArgument {
+
+ @Command(label = "f.setcolor", permission = "command.setcolor", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 3) {
+ Faction fac = Faction.getByName(args.getArg(1));
+ if(fac != null) {
+ SystemFaction sf = (SystemFaction) fac;
+
+ ChatColor color;
+ try {
+ color = ChatColor.valueOf(args.getArg(2).toUpperCase());
+ } catch(IllegalArgumentException ex) {
+ p.sendMessage(Locale.COMMAND_FACTION_SETCOLOR_INVALID.toString().replaceAll("%invalid%", args.getArg(2)));
+ return;
+ }
+
+ sf.setColor(color);
+ sf.save();
+
+ p.sendMessage(Locale.COMMAND_FACTION_SETCOLOR_SET.toString().replaceAll("%name%", sf.getName()).replaceAll("%color%", color + WordUtils.capitalizeFully(color.name())));
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "setcolor "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetDeathbanArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetDeathbanArgument.java
new file mode 100644
index 0000000..a053225
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetDeathbanArgument.java
@@ -0,0 +1,31 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionSetDeathbanArgument {
+
+ @Command(label = "f.setdeathban", permission = "command.setdeathban", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 3) {
+ Faction fac = Faction.getByName(args.getArg(1));
+ if(fac != null) {
+ boolean deathban = Boolean.valueOf(args.getArg(2));
+
+ fac.setDeathban(deathban);
+ fac.save();
+
+ p.sendMessage(Locale.COMMAND_FACTION_SETDEATHBAN_SET.toString().replaceAll("%name%", fac.getName()).replaceAll("%status%", deathban ? Locale.FACTION_DEATHBAN.toString() : Locale.FACTION_NONDEATHBAN.toString()));
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "setdeath "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetDtrArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetDtrArgument.java
new file mode 100644
index 0000000..d62decf
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetDtrArgument.java
@@ -0,0 +1,51 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.ui.tab.provider.HCFTablist;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionSetDtrArgument {
+
+ @Command(label = "f.setdtr", permission = "command.setdtr", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 3) {
+ Faction fac = Faction.getByName(args.getArg(1));
+
+ if(fac != null) {
+ if(fac instanceof PlayerFaction) {
+ PlayerFaction pf = (PlayerFaction) fac;
+
+ try {
+ double newDtr = Double.parseDouble(args.getArg(2));
+
+ if(newDtr > pf.getMaxDtr()) {
+ newDtr = pf.getMaxDtr();
+ }
+
+ pf.setDtr(newDtr);
+ pf.save();
+ p.sendMessage(Locale.COMMAND_FACTION_SETDTR_SET.toString().replaceAll("%name%", pf.getName()).replaceAll("%dtr%", String.valueOf(newDtr)));
+ pf.sendMessage(Locale.COMMAND_FACTION_SETDTR_SET_BC.toString().replaceAll("%name%", pf.getName()).replaceAll("%dtr%", String.valueOf(newDtr)));
+
+ for(Player player : pf.getOnlinePlayers())
+ HCFTablist.updateFaction(player);
+ } catch(NumberFormatException e) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_PLAYER.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "setdtr "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetRegenArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetRegenArgument.java
new file mode 100644
index 0000000..e4bd87e
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionSetRegenArgument.java
@@ -0,0 +1,48 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+import java.sql.Timestamp;
+import java.util.concurrent.TimeUnit;
+
+public class FactionSetRegenArgument {
+
+ @Command(label = "f.setregen", permission = "command.setregen", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 3) {
+ Faction fac = Faction.getByName(args.getArg(1));
+
+ if(fac != null) {
+ if(fac instanceof PlayerFaction) {
+ PlayerFaction pf = (PlayerFaction) fac;
+
+ try {
+ int seconds = Integer.parseInt(args.getArg(2));
+ if(seconds > 3600)
+ seconds = 3600;
+
+ pf.setStartRegen(new Timestamp(System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(seconds)));
+ pf.save();
+ p.sendMessage(Locale.COMMAND_FACTION_SETREGEN_SET.toString().replaceAll("%name%", pf.getName()).replaceAll("%minutes%", String.valueOf(TimeUnit.SECONDS.toMinutes(seconds))));
+ p.sendMessage(Locale.COMMAND_FACTION_SETREGEN_SET_BC.toString().replaceAll("%name%", pf.getName()).replaceAll("%minutes%", String.valueOf(TimeUnit.SECONDS.toMinutes(seconds))));
+ } catch(NumberFormatException e) {
+ p.sendMessage(Locale.INVALID_NUMBER.toString().replaceAll("%number%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_NOT_PLAYER.toString());
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "setregen "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionTeleportArgument.java b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionTeleportArgument.java
new file mode 100644
index 0000000..1149a88
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/command/args/staff/FactionTeleportArgument.java
@@ -0,0 +1,31 @@
+package me.hulipvp.hcf.game.faction.command.args.staff;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.api.command.Command;
+import me.hulipvp.hcf.api.command.CommandData;
+import org.bukkit.entity.Player;
+
+public class FactionTeleportArgument {
+
+ @Command(label = "f.teleport", aliases = {"f.tp"}, permission = "command.teleport", playerOnly = true)
+ public void onCommand(CommandData args) {
+ Player p = (Player) args.getSender();
+
+ if(args.length() == 2) {
+ Faction faction = Faction.getByName(args.getArg(1));
+ if(faction != null) {
+ if(faction.getHome() == null) {
+ p.sendMessage(Locale.COMMAND_FACTION_HOME_NOT_SET.toString());
+ } else {
+ p.teleport(faction.getHome());
+ p.sendMessage(Locale.FACTION_WARPING.toString().replaceAll("%faction%", faction.getName()));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_DOESNT_EXIST.toString().replaceAll("%faction%", args.getArg(1)));
+ }
+ } else {
+ p.sendMessage(Locale.COMMAND_FACTION_USAGE.toString().replaceAll("%data%", "teleport "));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/FactionType.java b/src/main/java/me/hulipvp/hcf/game/faction/type/FactionType.java
new file mode 100644
index 0000000..459f58c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/FactionType.java
@@ -0,0 +1,14 @@
+package me.hulipvp.hcf.game.faction.type;
+
+public enum FactionType {
+
+ PLAYER,
+ SAFEZONE,
+ WARZONE,
+ KOTH,
+ CONQUEST,
+ MOUNTAIN,
+ ROAD,
+ END_PORTAL,
+ SYSTEM
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/event/ConquestFaction.java b/src/main/java/me/hulipvp/hcf/game/faction/type/event/ConquestFaction.java
new file mode 100644
index 0000000..aef8e39
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/event/ConquestFaction.java
@@ -0,0 +1,31 @@
+package me.hulipvp.hcf.game.faction.type.event;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.conquest.Conquest;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.game.faction.type.system.SystemFaction;
+import org.bson.Document;
+import org.bukkit.ChatColor;
+
+import java.util.UUID;
+
+public class ConquestFaction extends SystemFaction {
+
+ @Getter private final Conquest conquest;
+
+ public ConquestFaction(UUID uuid, String name, Conquest conquest) {
+ super(uuid, name, true, FactionType.CONQUEST, ChatColor.YELLOW);
+
+ this.conquest = conquest;
+ }
+
+ @Override
+ public String getColoredName() {
+ return this.getColor() + "Conquest";
+ }
+
+ @Override
+ public Document toDocument() {
+ return super.toDocument().append("conquest", this.getConquest().getName());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/event/KothFaction.java b/src/main/java/me/hulipvp/hcf/game/faction/type/event/KothFaction.java
new file mode 100644
index 0000000..771548c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/event/KothFaction.java
@@ -0,0 +1,31 @@
+package me.hulipvp.hcf.game.faction.type.event;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.koth.Koth;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.game.faction.type.system.SystemFaction;
+import org.bson.Document;
+import org.bukkit.ChatColor;
+
+import java.util.UUID;
+
+public class KothFaction extends SystemFaction {
+
+ @Getter private final Koth koth;
+
+ public KothFaction(UUID uuid, String name, Koth koth) {
+ super(uuid, name, true, FactionType.KOTH, ChatColor.AQUA);
+
+ this.koth = koth;
+ }
+
+ @Override
+ public String getColoredName() {
+ return this.getColor() + this.getName() + ChatColor.GOLD + " KoTH";
+ }
+
+ @Override
+ public Document toDocument() {
+ return super.toDocument().append("koth", this.getKoth().getName());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/event/MountainFaction.java b/src/main/java/me/hulipvp/hcf/game/faction/type/event/MountainFaction.java
new file mode 100644
index 0000000..67c7fd9
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/event/MountainFaction.java
@@ -0,0 +1,34 @@
+package me.hulipvp.hcf.game.faction.type.event;
+
+import lombok.Getter;
+import me.hulipvp.hcf.game.event.mountain.Mountain;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.game.faction.type.system.SystemFaction;
+import org.bson.Document;
+import org.bukkit.ChatColor;
+
+import java.util.UUID;
+
+public class MountainFaction extends SystemFaction {
+
+ @Getter private final Mountain mountain;
+
+ public MountainFaction(UUID uuid, String name, Mountain mountain) {
+ super(uuid, name, true, FactionType.MOUNTAIN, ChatColor.YELLOW);
+
+ this.mountain = mountain;
+ }
+
+ @Override
+ public String getColoredName() {
+ return this.getColor() + this.getName() + ChatColor.GOLD + " Mountain";
+ }
+
+ @Override
+ public Document toDocument() {
+ if(mountain == null)
+ return super.toDocument();
+
+ return super.toDocument().append("mountain", this.getMountain().getName());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/player/FactionMember.java b/src/main/java/me/hulipvp/hcf/game/faction/type/player/FactionMember.java
new file mode 100644
index 0000000..f49a0aa
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/player/FactionMember.java
@@ -0,0 +1,33 @@
+package me.hulipvp.hcf.game.faction.type.player;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.UUID;
+
+public class FactionMember {
+
+ @Getter private final UUID uuid;
+ @Getter @Setter private FactionRank rank;
+
+ public FactionMember(UUID uuid, FactionRank rank) {
+ this.uuid = uuid;
+ this.rank = rank;
+ }
+
+ public boolean isAtLeast(FactionRank rank) {
+ return this.getRank().getRank() >= rank.getRank();
+ }
+
+ public String getStars() {
+ switch(this.getRank()) {
+ case LEADER:
+ case COLEADER:
+ return "**";
+ case CAPTAIN:
+ return "*";
+ default:
+ return "";
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/player/FactionRank.java b/src/main/java/me/hulipvp/hcf/game/faction/type/player/FactionRank.java
new file mode 100644
index 0000000..d7f084d
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/player/FactionRank.java
@@ -0,0 +1,26 @@
+package me.hulipvp.hcf.game.faction.type.player;
+
+import lombok.Getter;
+
+import java.util.Arrays;
+
+public enum FactionRank {
+
+ LEADER(4),
+ COLEADER(3),
+ CAPTAIN(2),
+ MEMBER(1);
+
+ @Getter private final int rank;
+
+ FactionRank(int rank) {
+ this.rank = rank;
+ }
+
+ public static FactionRank getByString(String string) {
+ return Arrays.stream(values())
+ .filter(rank -> rank.name().equalsIgnoreCase(string))
+ .findFirst()
+ .orElse(null);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/player/PlayerFaction.java b/src/main/java/me/hulipvp/hcf/game/faction/type/player/PlayerFaction.java
new file mode 100644
index 0000000..a911c29
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/player/PlayerFaction.java
@@ -0,0 +1,286 @@
+package me.hulipvp.hcf.game.faction.type.player;
+
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimer;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import org.bson.Document;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.scheduler.BukkitTask;
+
+import java.sql.Timestamp;
+import java.text.DecimalFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class PlayerFaction extends Faction {
+
+ @Getter @Setter private static List sorted = new ArrayList<>();
+
+ @Getter private final Map members;
+ @Getter private final List allies, requestedAllies, invited;
+
+ @Getter @Setter private FactionMember leader;
+ @Getter @Setter private double dtr;
+ @Getter @Setter private Timestamp startRegen;
+ @Getter @Setter private boolean regening, open;
+ @Getter @Setter private int lives, balance, kothCaptures;
+ @Getter @Setter private UUID focused;
+ @Getter @Setter private boolean powerFaction;
+ @Getter @Setter private String announcement;
+ @Getter @Setter private BukkitTask regenTask;
+
+ public PlayerFaction(UUID uuid, String name, UUID leader) {
+ super(uuid, name, true, FactionType.PLAYER);
+
+ this.leader = new FactionMember(leader, FactionRank.LEADER);
+ this.members = new HashMap<>();
+
+ if(leader != null)
+ this.members.put(this.getLeader().getUuid(), this.getLeader());
+
+ this.allies = new ArrayList<>();
+ this.requestedAllies = new ArrayList<>();
+ this.invited = new ArrayList<>();
+ this.dtr = 1.1;
+ this.startRegen = null;
+ this.regening = false;
+ this.lives = 0;
+ this.balance = 0;
+ this.powerFaction = false;
+ this.announcement = "";
+ this.regenTask = null;
+
+ this.setupRegenTask();
+ }
+
+ public void addMember(FactionMember member) {
+ this.getMembers().put(member.getUuid(), member);
+ }
+
+ public void removeMember(UUID uuid) {
+ this.getMembers().remove(uuid);
+ }
+
+ public List getOnlinePlayers() {
+ return members.keySet().parallelStream()
+ .map(Bukkit::getPlayer)
+ .filter(Objects::nonNull)
+ .filter(Player::isOnline)
+ .collect(Collectors.toList());
+ }
+
+ public int getOnlineCount() {
+ return this.getOnlinePlayers().size();
+ }
+
+ public void sendMessage(String message) {
+ this.getOnlinePlayers().forEach(ply -> ply.sendMessage(message));
+ }
+
+ public void sendExcludingMessage(Player player, String message) {
+ this.getOnlinePlayers().stream()
+ .filter(ply -> !player.getName().equalsIgnoreCase(ply.getName()))
+ .forEach(ply -> ply.sendMessage(message));
+ }
+
+ public void sendAllyMessage(String message) {
+ this.sendMessage(message);
+
+ for(UUID uuid : allies) {
+ PlayerFaction faction = getPlayerFaction(uuid);
+ if(faction != null)
+ faction.sendMessage(message);
+ }
+ }
+
+ public void sendCaptainMessage(String message) {
+ for(FactionMember member : this.getMembers().values()) {
+ if(member.isAtLeast(FactionRank.CAPTAIN)) {
+ Player player = Bukkit.getPlayer(member.getUuid());
+ if(player != null && player.isOnline())
+ player.sendMessage(message);
+ }
+ }
+ }
+
+ public boolean isAllied(UUID uuid) {
+ return this.getAllies().contains(uuid);
+ }
+
+ public void addAlly(UUID uuid) {
+ this.getAllies().add(uuid);
+ }
+
+ public void removeAlly(UUID uuid) {
+ this.getAllies().remove(uuid);
+ }
+
+ public boolean isRequestedAlly(UUID uuid) {
+ return this.getRequestedAllies().contains(uuid);
+ }
+
+ public void addRequestedAlly(UUID uuid) {
+ this.getRequestedAllies().add(uuid);
+ }
+
+ public void removeRequestedAlly(UUID uuid) {
+ this.getRequestedAllies().remove(uuid);
+ }
+
+ public boolean isInvited(UUID uuid) {
+ return this.getInvited().contains(uuid);
+ }
+
+ public void addInvite(UUID uuid) {
+ this.getInvited().add(uuid);
+ }
+
+ public void removeInvite(UUID uuid) {
+ this.getInvited().remove(uuid);
+ }
+
+ public double getMaxDtr() {
+ switch(members.size()) {
+ case 0:
+ case 1:
+ return 1.01;
+ case 2:
+ return 2.01;
+ case 3:
+ return 3.25;
+ case 4:
+ return 3.75;
+ case 5:
+ return 4.50;
+ default:
+ return 5.50;
+ }
+ }
+
+ public String getDtrSymbol() {
+ if(this.isRegening() || this.getDtr() != this.getMaxDtr())
+ return ChatColor.GREEN.toString() + '\u25B2';
+
+ if(this.getStartRegen() != null)
+ return ChatColor.RED.toString() + '\u25a0';
+
+ return ChatColor.GREEN.toString() + '\u25a0';
+ }
+
+ public String getDisplayString(UUID uuid) {
+ return this.getRelationColor(uuid) + this.getName() + " " + ((this.isDeathban()) ? Locale.FACTION_DEATHBAN.toString() : Locale.FACTION_NONDEATHBAN.toString());
+ }
+
+ public String getDisplayString(Player player) {
+ return getDisplayString(player.getUniqueId());
+ }
+
+ public String getRelationColor(Faction faction) {
+ return allies.contains(faction.getUuid()) ? ChatColor.LIGHT_PURPLE.toString() : ChatColor.RED.toString();
+ }
+
+ public String getRelationColor(UUID uuid) {
+ HCFProfile profile = HCFProfile.getByUuid(uuid);
+ if(!profile.hasFaction())
+ return ChatColor.RED.toString();
+
+ if(isAllied(uuid))
+ return ChatColor.LIGHT_PURPLE.toString();
+
+ return this.getMembers().containsKey(uuid) ? ChatColor.GREEN.toString() : ChatColor.RED.toString();
+ }
+
+ public String getRelationColor(Player player) {
+ return getRelationColor(player.getUniqueId());
+ }
+
+ public boolean isRaidable() {
+ return this.getDtr() <= 0;
+ }
+
+ public void setupRegenTask() {
+ this.regenTask = new BukkitRunnable() {
+ @Override
+ public void run() {
+ if(getOnlineCount() == 0)
+ return;
+ if(ServerTimer.isEotw()) {
+ cancel();
+ return;
+ }
+
+ if(getStartRegen() == null) {
+ if(getDtr() < getMaxDtr()) {
+ DecimalFormat df = new DecimalFormat("#.##");
+ String newDtr = df.format(getDtr() + ConfigValues.FACTIONS_DTR_REGEN_INCREMENT);
+ setDtr(Double.valueOf(newDtr));
+ } else {
+ setDtr(getMaxDtr());
+ setRegening(false);
+ setStartRegen(null);
+ regenTask.cancel();
+ this.cancel();
+ }
+ } else {
+ if(getStartRegen().after(new Timestamp(System.currentTimeMillis())))
+ return;
+
+ setStartRegen(null);
+ setRegening(true);
+ sendMessage(C.color("&e&lYour faction is now regenerating DTR."));
+ }
+ }
+ }.runTaskTimerAsynchronously(HCF.getInstance(), 2L, 20L * ConfigValues.FACTIONS_DTR_REGEN_DELAY);
+ }
+
+ @Override
+ public Document toDocument() {
+ Document doc = super.toDocument().append("leader", this.getLeader().getUuid().toString() + ";" + this.getLeader().getRank().toString() + ";");
+
+ BasicDBObject members = new BasicDBObject();
+ BasicDBList allies = new BasicDBList();
+ BasicDBList requestedAllies = new BasicDBList();
+ BasicDBList invited = new BasicDBList();
+
+ for(FactionMember member : this.getMembers().values())
+ members.append(member.getUuid().toString(), member.getRank().toString());
+
+ for(UUID ally : this.getAllies())
+ allies.add(ally.toString());
+
+ for(UUID ally : this.getRequestedAllies())
+ requestedAllies.add(ally.toString());
+
+ for(UUID invitee : this.getInvited())
+ invited.add(invitee.toString());
+
+ doc.append("members", members);
+ doc.append("allies", allies);
+ doc.append("requestedAllies", requestedAllies);
+ doc.append("invited", invited);
+ doc.append("dtr", this.getDtr());
+ doc.append("startRegen", ((this.getStartRegen() == null) ? null : TimeUtils.serializeTimestamp(this.getStartRegen())));
+ doc.append("regening", this.isRegening());
+ doc.append("open", this.isOpen());
+ doc.append("lives", this.getLives());
+ doc.append("kothCaptures", this.getKothCaptures());
+ doc.append("balance", this.getBalance());
+ doc.append("powerfaction", this.isPowerFaction());
+ doc.append("announcement", this.getAnnouncement());
+
+ return doc;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/system/EndPortalFaction.java b/src/main/java/me/hulipvp/hcf/game/faction/type/system/EndPortalFaction.java
new file mode 100644
index 0000000..445b9de
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/system/EndPortalFaction.java
@@ -0,0 +1,11 @@
+package me.hulipvp.hcf.game.faction.type.system;
+
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import org.bukkit.ChatColor;
+
+public class EndPortalFaction extends SystemFaction {
+
+ public EndPortalFaction() {
+ super(null, "End_Portal", true, FactionType.END_PORTAL, ChatColor.GOLD);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/system/RoadFaction.java b/src/main/java/me/hulipvp/hcf/game/faction/type/system/RoadFaction.java
new file mode 100644
index 0000000..aa8b582
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/system/RoadFaction.java
@@ -0,0 +1,18 @@
+package me.hulipvp.hcf.game.faction.type.system;
+
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import org.bukkit.ChatColor;
+
+import java.util.UUID;
+
+public class RoadFaction extends SystemFaction {
+
+ public RoadFaction(UUID uuid, String name) {
+ super(uuid, name, FactionType.ROAD, ChatColor.GOLD);
+ }
+
+ @Override
+ public String getColoredName() {
+ return this.getColor() + this.getName() + " Road";
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/system/SafezoneFaction.java b/src/main/java/me/hulipvp/hcf/game/faction/type/system/SafezoneFaction.java
new file mode 100644
index 0000000..f199be2
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/system/SafezoneFaction.java
@@ -0,0 +1,13 @@
+package me.hulipvp.hcf.game.faction.type.system;
+
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import org.bukkit.ChatColor;
+
+import java.util.UUID;
+
+public class SafezoneFaction extends SystemFaction {
+
+ public SafezoneFaction(UUID uuid, String name) {
+ super(uuid, name, false, FactionType.SAFEZONE, ChatColor.GREEN);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/system/SystemFaction.java b/src/main/java/me/hulipvp/hcf/game/faction/type/system/SystemFaction.java
new file mode 100644
index 0000000..a0de07c
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/system/SystemFaction.java
@@ -0,0 +1,46 @@
+package me.hulipvp.hcf.game.faction.type.system;
+
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.StringUtils;
+import lombok.Getter;
+import lombok.Setter;
+import org.bson.Document;
+import org.bukkit.ChatColor;
+
+import java.util.UUID;
+
+public class SystemFaction extends Faction {
+
+ @Getter @Setter private ChatColor color;
+
+ public SystemFaction(UUID uuid, String name, boolean deathban, FactionType type, ChatColor color) {
+ super(uuid, name, deathban, type);
+
+ this.color = color;
+ }
+
+ public SystemFaction(UUID uuid, String name, FactionType type, ChatColor color) {
+ this(uuid, name, true, type, color);
+ }
+
+ public SystemFaction(UUID uuid, String name) {
+ this(uuid, name, true, FactionType.SYSTEM, ChatColor.WHITE);
+ }
+
+ public String getColoredName() {
+ return this.getColor() + this.getName();
+ }
+
+ @Override
+ public String getDisplayString() {
+ return C.color(this.getColoredName() + " " + ((this.isDeathban()) ? Locale.FACTION_DEATHBAN.toString() : Locale.FACTION_NONDEATHBAN.toString()));
+ }
+
+ @Override
+ public Document toDocument() {
+ return super.toDocument().append("color", StringUtils.chatColorToString(this.getColor()));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/faction/type/system/WarzoneFaction.java b/src/main/java/me/hulipvp/hcf/game/faction/type/system/WarzoneFaction.java
new file mode 100644
index 0000000..509a477
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/faction/type/system/WarzoneFaction.java
@@ -0,0 +1,22 @@
+package me.hulipvp.hcf.game.faction.type.system;
+
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.utils.ConfigValues;
+import org.bukkit.ChatColor;
+
+import java.util.UUID;
+
+public class WarzoneFaction extends SystemFaction {
+
+ public WarzoneFaction(UUID uuid) {
+ super(uuid, "Warzone", FactionType.WARZONE, ChatColor.RED);
+ }
+
+ @Override
+ public String getHomeString() {
+ if(ConfigValues.FACTIONS_SIZE_WARZONE > 0)
+ return ConfigValues.FACTIONS_SIZE_WARZONE + " | " + ConfigValues.FACTIONS_SIZE_WARZONE;
+
+ return super.getHomeString();
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/kits/EffectRestoreTask.java b/src/main/java/me/hulipvp/hcf/game/kits/EffectRestoreTask.java
new file mode 100644
index 0000000..42f0104
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/kits/EffectRestoreTask.java
@@ -0,0 +1,42 @@
+package me.hulipvp.hcf.game.kits;
+
+import lombok.Getter;
+import org.bukkit.entity.Player;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class EffectRestoreTask extends BukkitRunnable {
+
+ @Getter private final Player player;
+ @Getter private final PotionEffect before;
+
+ public EffectRestoreTask(Player player, PotionEffect before) {
+ this.player = player;
+ this.before = before;
+ }
+
+ @Override
+ public void run() {
+ if(!player.isOnline()) {
+ cancel();
+ return;
+ }
+
+ if(player.hasPotionEffect(before.getType())) {
+ PotionEffect effect = player.getActivePotionEffects().stream()
+ .filter(potionEffect -> potionEffect.getType() == before.getType())
+ .findFirst().orElse(null);
+ if(effect == null)
+ return;
+
+ if(effect.getAmplifier() == before.getAmplifier()) {
+ if(before.getDuration() > effect.getDuration())
+ player.addPotionEffect(before, true);
+ } else {
+ player.addPotionEffect(before, true);
+ }
+ } else {
+ player.addPotionEffect(before);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/game/kits/Kit.java b/src/main/java/me/hulipvp/hcf/game/kits/Kit.java
new file mode 100644
index 0000000..6261672
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/kits/Kit.java
@@ -0,0 +1,136 @@
+package me.hulipvp.hcf.game.kits;
+
+import lombok.Getter;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.events.kit.KitDisableEvent;
+import me.hulipvp.hcf.api.events.kit.KitEnableEvent;
+import me.hulipvp.hcf.game.kits.type.*;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Listener;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.ShapedRecipe;
+import org.bukkit.potion.PotionEffect;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public abstract class Kit implements Listener {
+
+ @Getter private static final Map kits = new HashMap<>();
+
+ @Getter private final String name;
+ @Getter private final ArmorType type;
+ @Getter private final List effects;
+
+ public Kit(String name, ArmorType type, List effects) {
+ this.name = name;
+ this.type = type;
+ this.effects = effects;
+ }
+
+ public static Kit getByType(ArmorType type) {
+ return kits.values().stream()
+ .filter(kit -> kit.getType() == type)
+ .findFirst()
+ .orElse(null);
+ }
+
+ public static boolean isWearingKit(Player p, ArmorType type) {
+ if(p.getInventory().getHelmet() == null || p.getInventory().getChestplate() == null || p.getInventory().getLeggings() == null || p.getInventory().getBoots() == null)
+ return false;
+
+ switch(type) {
+ case DIAMOND:
+ return p.getInventory().getHelmet().getType() == Material.DIAMOND_HELMET && p.getInventory().getChestplate().getType() == Material.DIAMOND_CHESTPLATE && p.getInventory().getLeggings().getType() == Material.DIAMOND_LEGGINGS && p.getInventory().getBoots().getType() == Material.DIAMOND_BOOTS;
+ case GOLD:
+ return p.getInventory().getHelmet().getType() == Material.GOLD_HELMET && p.getInventory().getChestplate().getType() == Material.GOLD_CHESTPLATE && p.getInventory().getLeggings().getType() == Material.GOLD_LEGGINGS && p.getInventory().getBoots().getType() == Material.GOLD_BOOTS;
+ case IRON:
+ return p.getInventory().getHelmet().getType() == Material.IRON_HELMET && p.getInventory().getChestplate().getType() == Material.IRON_CHESTPLATE && p.getInventory().getLeggings().getType() == Material.IRON_LEGGINGS && p.getInventory().getBoots().getType() == Material.IRON_BOOTS;
+ case CHAIN:
+ return p.getInventory().getHelmet().getType() == Material.CHAINMAIL_HELMET && p.getInventory().getChestplate().getType() == Material.CHAINMAIL_CHESTPLATE && p.getInventory().getLeggings().getType() == Material.CHAINMAIL_LEGGINGS && p.getInventory().getBoots().getType() == Material.CHAINMAIL_BOOTS;
+ case LEATHER:
+ return p.getInventory().getHelmet().getType() == Material.LEATHER_HELMET && p.getInventory().getChestplate().getType() == Material.LEATHER_CHESTPLATE && p.getInventory().getLeggings().getType() == Material.LEATHER_LEGGINGS && p.getInventory().getBoots().getType() == Material.LEATHER_BOOTS;
+ }
+ return false;
+ }
+
+ public static void instate() {
+ if(ConfigValues.KITS_ARCHER_ENABLE) {
+ Kit archer = new ArcherKit();
+ kits.put(archer.getName(), archer);
+ }
+
+ if(ConfigValues.KITS_BARD_ENABLE) {
+ Kit bard = new BardKit();
+ kits.put(bard.getName(), bard);
+ }
+
+ if(ConfigValues.KITS_MINER_ENABLE) {
+ Kit miner = new MinerKit();
+ kits.put(miner.getName(), miner);
+ }
+
+ if(ConfigValues.KITS_ROGUE_ENABLE) {
+ Kit rogue = new RougeKit();
+ kits.put(rogue.getName(), rogue);
+ }
+
+ for(Kit kit : kits.values())
+ Bukkit.getServer().getPluginManager().registerEvents(kit, HCF.getInstance());
+
+ Bukkit.getScheduler().runTaskTimerAsynchronously(HCF.getInstance(), () -> {
+ for(Player player : Bukkit.getOnlinePlayers()) {
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+
+ if(profile.getCurrentKit() != null) {
+ if(!isWearingKit(player, profile.getCurrentKit().getType())) {
+ for(PotionEffect effect : profile.getCurrentKit().getEffects())
+ player.removePotionEffect(effect.getType());
+
+ KitDisableEvent kitDisableEvent = new KitDisableEvent(player, profile.getCurrentKit());
+ Bukkit.getPluginManager().callEvent(kitDisableEvent);
+
+ profile.setCurrentKit(null);
+ break;
+ } else {
+ profile.getCurrentKit().getEffects().forEach(player::addPotionEffect);
+
+ if(profile.getCurrentKit().getType() == ArmorType.GOLD) {
+ ((BardKit) profile.getCurrentKit()).applyHeldBard(player, player.getItemInHand());
+
+ if(BardKit.getPlayerEnergy().get(profile.getUuid().toString()) < ConfigValues.KITS_BARD_MAX_ENERGY)
+ BardKit.getPlayerEnergy().put(profile.getUuid().toString(), BardKit.getPlayerEnergy().get(profile.getUuid().toString()) + 1);
+ }
+ }
+ } else {
+ for(ArmorType type : ArmorType.values()) {
+ if(isWearingKit(player, type)) {
+ Kit kit = getByType(type);
+ if(kit != null) {
+ kit.getEffects().forEach(player::addPotionEffect);
+
+ KitEnableEvent kitEnableEvent = new KitEnableEvent(player, kit);
+ Bukkit.getPluginManager().callEvent(kitEnableEvent);
+
+ profile.setCurrentKit(kit);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }, 20L, 20L);
+
+ ShapedRecipe easyMelon = new ShapedRecipe(new ItemStack(Material.SPECKLED_MELON, 1));
+ easyMelon.shape(" ", "AB ", " ")
+ .setIngredient('A', Material.MELON)
+ .setIngredient('B', Material.GOLD_NUGGET);
+
+ Bukkit.addRecipe(easyMelon);
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/kits/MapKit.java b/src/main/java/me/hulipvp/hcf/game/kits/MapKit.java
new file mode 100644
index 0000000..8d4c4b6
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/kits/MapKit.java
@@ -0,0 +1,24 @@
+package me.hulipvp.hcf.game.kits;
+
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.game.player.data.PlayerInv;
+import org.apache.commons.lang.WordUtils;
+import org.bukkit.ChatColor;
+
+public class MapKit {
+
+ @Getter private final String name;
+
+ @Getter @Setter private boolean enabled;
+ @Getter @Setter private ChatColor color;
+ @Getter @Setter private PlayerInv playerInv;
+
+ public MapKit(String name) {
+ this.name = name;
+ }
+
+ public String getDisplay() {
+ return this.getColor() + WordUtils.capitalizeFully(this.getName());
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/kits/type/ArcherKit.java b/src/main/java/me/hulipvp/hcf/game/kits/type/ArcherKit.java
new file mode 100644
index 0000000..970d2cd
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/kits/type/ArcherKit.java
@@ -0,0 +1,171 @@
+package me.hulipvp.hcf.game.kits.type;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.system.SafezoneFaction;
+import me.hulipvp.hcf.game.kits.Kit;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimer;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimerType;
+import me.hulipvp.hcf.game.timer.type.server.ServerTimer;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import org.bukkit.Material;
+import org.bukkit.entity.Arrow;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Projectile;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.Arrays;
+
+public class ArcherKit extends Kit {
+
+ public ArcherKit() {
+ super("Archer", ArmorType.LEATHER, Arrays.asList(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 2, false), new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, Integer.MAX_VALUE, 1, false)));
+ }
+
+ @EventHandler
+ public void onEntityDamage(EntityDamageByEntityEvent e) {
+ if(!(e.getEntity() instanceof Player))
+ return;
+ if(ServerTimer.isSotw()) {
+ e.setDamage(0.0);
+ e.setCancelled(true);
+ return;
+ }
+
+
+ Player target = (Player) e.getEntity();
+ HCFProfile profile = HCFProfile.getByPlayer(target);
+ if(profile.hasTimer(PlayerTimerType.STARTING) || profile.hasTimer(PlayerTimerType.PVPTIMER)) {
+ e.setCancelled(true);
+
+ if(e.getDamager() instanceof Player)
+ ((Player) e.getDamager()).sendMessage(Locale.TIMER_ATTACK_PROTECTED.toString());
+ return;
+ }
+
+ if(Faction.getByLocation(target.getLocation()) instanceof SafezoneFaction) {
+ e.setDamage(0.0);
+ e.setCancelled(true);
+ return;
+ }
+
+ if(e.getCause() == EntityDamageEvent.DamageCause.PROJECTILE) {
+ Projectile proj = (Projectile) e.getDamager();
+ if(!(proj instanceof Arrow))
+ return;
+
+ Arrow arrow = (Arrow) proj;
+ Player damager = (Player) arrow.getShooter();
+ if(Faction.getByLocation(damager.getLocation()) instanceof SafezoneFaction){
+ e.setDamage(0.0);
+ e.setCancelled(true);
+ return;
+ }
+
+ if(profile.getFactionObj() != null) {
+ if(profile.getFactionObj().getMembers().containsKey(damager.getUniqueId())) {
+ e.setCancelled(true);
+ return;
+ }
+ }
+
+ HCFProfile damagerProfile = HCFProfile.getByPlayer(damager);
+ if(damagerProfile.hasTimer(PlayerTimerType.STARTING) || damagerProfile.hasTimer(PlayerTimerType.PVPTIMER)) {
+ e.setCancelled(true);
+ damager.sendMessage(Locale.TIMER_PROTECTED.toString());
+ return;
+ }
+
+ if(!Kit.isWearingKit(damager, this.getType())) {
+ if(profile.hasTimer(PlayerTimerType.ARCHERMARK)) {
+ double dmg = e.getDamage() + (2.5 * TimeUtils.random.nextInt(100) / 100.0);
+ e.setDamage(dmg);
+ }
+ return;
+ }
+
+ double range = Math.round(arrow.getLocation().distance(damager.getLocation()));
+ if(!Kit.isWearingKit(target, this.getType())) {
+ double dmg = e.getDamage(EntityDamageEvent.DamageModifier.BASE) + (3.5 * (TimeUtils.random.nextInt(100) / 100.0));
+ e.setDamage(dmg);
+
+ damager.sendMessage(Locale.ARCHER_TAG.toString().replaceAll("%range%", String.valueOf(range)).replaceAll("%time%", String.valueOf(PlayerTimerType.ARCHERMARK.getDefaultTime())).replaceAll("%hearts%", String.valueOf(Math.ceil((e.getFinalDamage() / 2.0) * 2) / 2.0)));
+
+ PlayerTimer timer = profile.getTimerByType(PlayerTimerType.ARCHERMARK);
+ if(timer == null) {
+ timer = new PlayerTimer(target, PlayerTimerType.ARCHERMARK);
+ timer.add();
+ } else {
+ timer.setCurrentTime(timer.getLength(), false);
+ }
+ } else {
+ damager.sendMessage(Locale.ARCHER_CANNOT_TAG.toString().replaceAll("%range%", String.valueOf(range)).replaceAll("%time%", String.valueOf(PlayerTimerType.ARCHERMARK.getDefaultTime())).replaceAll("%hearts%", String.valueOf(Math.ceil((e.getFinalDamage() / 2.0) * 2) / 2.0)));
+ }
+ } else {
+ if(profile.hasTimer(PlayerTimerType.ARCHERMARK)) {
+ double dmg = e.getDamage() + (3.0 * (TimeUtils.random.nextInt(100) / 100.0));
+
+ e.setDamage(dmg);
+// target.damage(dmg);
+ }
+ }
+ }
+
+ @EventHandler
+ public void onInteract(PlayerInteractEvent e) {
+ if(!e.getAction().name().contains("RIGHT"))
+ return;
+ if(!Kit.isWearingKit(e.getPlayer(), this.getType()))
+ return;
+ if(!e.hasItem())
+ return;
+ if(e.getItem().getType() != Material.SUGAR && e.getItem().getType() != Material.FEATHER)
+ return;
+
+ PlayerTimerType timerType = e.getItem().getType() == Material.FEATHER ? PlayerTimerType.JUMP_EFFECT : PlayerTimerType.SPEED_EFFECT;
+ PotionEffectType potionType = e.getItem().getType() == Material.FEATHER ? PotionEffectType.JUMP : PotionEffectType.SPEED;
+
+ HCFProfile profile = HCFProfile.getByPlayer(e.getPlayer());
+ PlayerTimer timer = profile.getTimerByType(timerType);
+ if(timer == null) {
+ timer = new PlayerTimer(e.getPlayer(), timerType);
+ timer.add();
+
+ e.getPlayer().removePotionEffect(potionType);
+ e.getPlayer().addPotionEffect(new PotionEffect(potionType, 10 * 20, 3, false));
+
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if(!Kit.isWearingKit(e.getPlayer(), getType()))
+ return;
+
+ getEffects().stream()
+ .filter(effect -> effect.getType() == potionType)
+ .forEach(effect -> {
+ e.getPlayer().addPotionEffect(effect, true);
+ });
+ }
+ }.runTaskLater(HCF.getInstance(), 190L);
+
+ int newAmount = e.getItem().getAmount() - 1;
+ if(newAmount == 0)
+ e.getPlayer().setItemInHand(new ItemStack(Material.AIR, 1));
+ else
+ e.getItem().setAmount(newAmount);
+ e.getPlayer().updateInventory();
+ } else {
+ e.setCancelled(true);
+ e.getPlayer().sendMessage(Locale.TIMER_CANNOT_USE.toString().replaceAll("%time%", timer.getFormattedTime().replaceAll("s", "")));
+ }
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/kits/type/ArmorType.java b/src/main/java/me/hulipvp/hcf/game/kits/type/ArmorType.java
new file mode 100644
index 0000000..d958dd5
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/kits/type/ArmorType.java
@@ -0,0 +1,10 @@
+package me.hulipvp.hcf.game.kits.type;
+
+public enum ArmorType {
+
+ DIAMOND,
+ GOLD,
+ IRON,
+ CHAIN,
+ LEATHER
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/kits/type/BardKit.java b/src/main/java/me/hulipvp/hcf/game/kits/type/BardKit.java
new file mode 100644
index 0000000..9a81395
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/kits/type/BardKit.java
@@ -0,0 +1,320 @@
+package me.hulipvp.hcf.game.kits.type;
+
+import lombok.Getter;
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.kits.EffectRestoreTask;
+import me.hulipvp.hcf.game.kits.Kit;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimer;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimerType;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.Material;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerItemHeldEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+public class BardKit extends Kit {
+
+ @Getter private static final Map playerEnergy = new HashMap<>();
+ @Getter private Map energyMap = new HashMap<>();
+
+ public BardKit() {
+ super("Bard", ArmorType.GOLD, Arrays.asList(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 1, false), new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, Integer.MAX_VALUE, 1, false), new PotionEffect(PotionEffectType.REGENERATION, Integer.MAX_VALUE, 0, false)));
+
+ energyMap.put(Material.IRON_INGOT, 40);
+ energyMap.put(Material.BLAZE_POWDER, 45);
+ energyMap.put(Material.FEATHER, 20);
+ energyMap.put(Material.SUGAR, 30);
+ energyMap.put(Material.SPIDER_EYE, 40);
+ energyMap.put(Material.GHAST_TEAR, 35);
+ }
+
+ @EventHandler
+ public void onHeldItem(PlayerItemHeldEvent event) {
+ if(!Kit.isWearingKit(event.getPlayer(), this.getType()))
+ return;
+
+ Player player = event.getPlayer();
+ ItemStack oldItem = player.getInventory().getItem(event.getPreviousSlot());
+ if(oldItem != null && oldItem.getType() != Material.AIR) {
+ PotionEffect effect = getHeldEffect(oldItem);
+ if(effect != null)
+ removeEffects(player, effect);
+ }
+
+ ItemStack newItem = player.getInventory().getItem(event.getNewSlot());
+ if(newItem == null || newItem.getType() == Material.AIR)
+ return;
+
+ applyHeldBard(player, newItem);
+ }
+
+ @EventHandler
+ public void onInteract(PlayerInteractEvent event) {
+ if(!Kit.isWearingKit(event.getPlayer(), this.getType()))
+ return;
+ if(!event.getAction().name().contains("RIGHT"))
+ return;
+ if(!event.hasItem() || !isValidItem(event.getItem().getType()))
+ return;
+
+ Player player = event.getPlayer();
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+ Faction otherFaction = Faction.getByLocation(player.getLocation());
+ if(otherFaction != null && !otherFaction.isDeathban()) {
+ player.sendMessage(Locale.BARD_SAFEZONE.toString());
+ return;
+ }
+
+ PlayerTimer timer = profile.getTimerByType(PlayerTimerType.BARD_EFFECT);
+ if(timer == null) {
+ if(applyInstantBard(player, event.getItem())) {
+ timer = new PlayerTimer(player, PlayerTimerType.BARD_EFFECT);
+ timer.add();
+
+ int newAmount = event.getItem().getAmount() - 1;
+ if(newAmount == 0)
+ event.getPlayer().setItemInHand(new ItemStack(Material.AIR, 1));
+ else
+ event.getItem().setAmount(newAmount);
+ event.getPlayer().updateInventory();
+ }
+ } else {
+ event.setCancelled(true);
+ event.getPlayer().sendMessage(Locale.TIMER_CANNOT_USE.toString().replaceAll("%time%", timer.getFormattedTime().replaceAll("s", "")));
+ }
+ }
+
+ private boolean applyInstantBard(Player player, ItemStack item) {
+ if(item != null) {
+ Material type = item.getType();
+
+ if(isValidItem(type)) {
+ int energyToConsume = energyMap.get(type);
+ int energy = playerEnergy.get(player.getUniqueId().toString());
+ if(energy < energyToConsume) {
+ player.sendMessage(Locale.BARD_NOT_ENOUGH.toString());
+ return false;
+ }
+
+ PotionEffect effect = null;
+ switch(type) {
+ case IRON_INGOT:
+ effect = new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 100, 3);
+ break;
+ case BLAZE_POWDER:
+ effect = new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 110, 1);
+ break;
+ case FEATHER:
+ effect = new PotionEffect(PotionEffectType.JUMP, 100, 3);
+ break;
+ case SUGAR:
+ effect = new PotionEffect(PotionEffectType.SPEED, 100, 2);
+ break;
+ case SPIDER_EYE:
+ effect = new PotionEffect(PotionEffectType.WITHER, 100, 0);
+ break;
+ case GHAST_TEAR:
+ effect = new PotionEffect(PotionEffectType.REGENERATION, 100, 2);
+ break;
+ }
+
+ if(effect != null) {
+ applyEffects(player, effect, type == Material.SPIDER_EYE);
+ playerEnergy.put(player.getUniqueId().toString(), energy - energyToConsume);
+ player.sendMessage(Locale.BARD_USED_EFFECT.toString().replaceAll("%effect%", getEffectName(type))
+ .replaceAll("%energy%", String.valueOf(energyToConsume)));
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private PotionEffect getHeldEffect(ItemStack item) {
+ if(item == null)
+ return null;
+
+ Material type = item.getType();
+ PotionEffect effect = null;
+
+ switch(type) {
+ case IRON_INGOT:
+ effect = new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, 100, 0);
+ break;
+ case BLAZE_POWDER:
+ effect = new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 100, 0);
+ break;
+ case FEATHER:
+ effect = new PotionEffect(PotionEffectType.JUMP, 100, 1);
+ break;
+ case SUGAR:
+ effect = new PotionEffect(PotionEffectType.SPEED, 100, 1);
+ break;
+ case GHAST_TEAR:
+ effect = new PotionEffect(PotionEffectType.REGENERATION, 100, 0);
+ break;
+ }
+
+ return effect;
+ }
+
+ public void applyHeldBard(Player player, ItemStack item) {
+ if(item != null) {
+ PotionEffect effect = getHeldEffect(item);
+
+ if(effect != null)
+ applyEffects(player, effect, false);
+ }
+ }
+
+ private String getEffectName(Material mat) {
+ switch(mat) {
+ case IRON_INGOT:
+ return "Resistance IV";
+ case BLAZE_POWDER:
+ return "Strength II";
+ case FEATHER:
+ return "Jump IV";
+ case SUGAR:
+ return "Speed III";
+ case SPIDER_EYE:
+ return "Wither I";
+ case GHAST_TEAR:
+ return "Regeneration III";
+ default: {
+ return "Unknown Effect";
+ }
+ }
+ }
+
+ private boolean isValidItem(Material type) {
+ return energyMap.containsKey(type);
+ }
+
+ private void applyEffect(Player player, PotionEffect effect) {
+ if(canOverrideLevel(player, effect) && player.hasPotionEffect(effect.getType())) {
+ PotionEffect temp = player.getActivePotionEffects().stream()
+ .filter(potionEffect -> potionEffect.getType().getName().equals(effect.getType().getName()))
+ .findFirst()
+ .orElse(null);
+ if(temp == null)
+ return;
+
+ PotionEffect pre = new PotionEffect(temp.getType(), temp.getDuration(), temp.getAmplifier(), temp.isAmbient());
+ new EffectRestoreTask(player, pre).runTaskLater(HCF.getInstance(), effect.getDuration() - 5);
+ }
+
+ if(canOverrideLevel(player, effect)) {
+ player.addPotionEffect(effect, true);
+
+ if(effect.getType() == PotionEffectType.WITHER) {
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+ if(profile.hasTimer(PlayerTimerType.COMBAT)) {
+ profile.updateTimer(PlayerTimerType.COMBAT, 30L, true);
+ } else {
+ PlayerTimer timer = new PlayerTimer(player, PlayerTimerType.COMBAT);
+ timer.add();
+ }
+ }
+ }
+ }
+
+ private void applyEffects(Player player, PotionEffect effect, boolean negative) {
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+ PlayerFaction faction = profile.getFactionObj();
+ int range = ConfigValues.KITS_BARD_EFFECT_RANGE;
+
+ if(faction != null) {
+ for(Entity entity : player.getNearbyEntities(range, range, range)) {
+ if(!(entity instanceof Player))
+ continue;
+
+ Player p = (Player) entity;
+ HCFProfile other = HCFProfile.getByPlayer(p);
+ if(negative) {
+ if(other.hasFaction() && (other.getFaction().equals(faction.getUuid()) || faction.isAllied(other.getFaction())))
+ continue;
+
+ applyEffect(p, effect);
+ } else {
+ if(!other.hasFaction())
+ continue;
+ if(!other.getFaction().equals(faction.getUuid()) && !faction.isAllied(other.getFaction()))
+ continue;
+
+ applyEffect(p, effect);
+ }
+ }
+ }
+
+ if(effect.getType() == PotionEffectType.INCREASE_DAMAGE && effect.getAmplifier() >= 1)
+ return;
+
+ applyEffect(player, effect);
+ }
+
+ private void removeEffects(Player player, PotionEffect effect) {
+ HCFProfile profile = HCFProfile.getByPlayer(player);
+ PlayerFaction faction = profile.getFactionObj();
+ int range = ConfigValues.KITS_BARD_EFFECT_RANGE;
+
+ if(faction != null) {
+ for(Entity entity : player.getNearbyEntities(range, range, range)) {
+ if(!(entity instanceof Player))
+ continue;
+
+ Player p = (Player) entity;
+ HCFProfile other = HCFProfile.getByPlayer(p);
+ if(!other.hasFaction())
+ continue;
+ if(!other.getFaction().equals(faction.getUuid()) && !faction.isAllied(other.getFaction()))
+ continue;
+
+ removeEffect(p, effect);
+ }
+ }
+
+ removeEffect(player, effect);
+ }
+
+ private void removeEffect(Player player, PotionEffect effect) {
+ if(!player.hasPotionEffect(effect.getType()))
+ return;
+
+ PotionEffect toRemove = player.getActivePotionEffects().stream().filter(potionEffect -> potionEffect.getType().getId() == effect.getType().getId()).findFirst().orElse(null);
+ if(toRemove == null)
+ return;
+ if(toRemove.getAmplifier() != effect.getAmplifier())
+ return;
+ if(toRemove.getDuration() > effect.getDuration())
+ return;
+
+ player.removePotionEffect(effect.getType());
+ }
+
+ private boolean canOverrideLevel(Player player, PotionEffect effect) {
+ if(player.hasPotionEffect(effect.getType())) {
+ PotionEffect before = player.getActivePotionEffects().stream().filter(potionEffect -> potionEffect.getType().getId() == effect.getType().getId()).findFirst().orElse(null);
+ if(before == null)
+ return true;
+
+ return before.getAmplifier() < effect.getAmplifier() || (before.getAmplifier() == effect.getAmplifier() && before.getDuration() < effect.getDuration());
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/me/hulipvp/hcf/game/kits/type/MinerKit.java b/src/main/java/me/hulipvp/hcf/game/kits/type/MinerKit.java
new file mode 100644
index 0000000..80ea6da
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/kits/type/MinerKit.java
@@ -0,0 +1,48 @@
+package me.hulipvp.hcf.game.kits.type;
+
+import me.hulipvp.hcf.utils.ConfigValues;
+import me.hulipvp.hcf.game.kits.Kit;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.utils.Locale;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+
+import java.util.Arrays;
+
+public class MinerKit extends Kit {
+
+ public MinerKit() {
+ super("Miner", ArmorType.IRON, Arrays.asList(new PotionEffect(PotionEffectType.FAST_DIGGING, Integer.MAX_VALUE, 1, false), new PotionEffect(PotionEffectType.FIRE_RESISTANCE, Integer.MAX_VALUE, 0, false), new PotionEffect(PotionEffectType.NIGHT_VISION, Integer.MAX_VALUE, 0, false)));
+ }
+
+ @EventHandler
+ public void onMove(PlayerMoveEvent event) {
+ if(!Kit.isWearingKit(event.getPlayer(), this.getType()))
+ return;
+ if(event.getFrom().getBlockY() == event.getTo().getBlockY())
+ return;
+
+ Player player = event.getPlayer();
+ int level = player.getLocation().getBlockY();
+
+ boolean sendMessage = false;
+ if(level <= ConfigValues.KITS_MINER_INVIS_LEVEL) {
+ if(!player.hasPotionEffect(PotionEffectType.INVISIBILITY)) {
+ player.addPotionEffect(new PotionEffect(PotionEffectType.INVISIBILITY, Integer.MAX_VALUE, 1, false));
+ sendMessage = true;
+ }
+ } else {
+ if(player.hasPotionEffect(PotionEffectType.INVISIBILITY)) {
+ player.removePotionEffect(PotionEffectType.INVISIBILITY);
+ sendMessage = true;
+ }
+ }
+
+ if(sendMessage)
+ player.sendMessage(Locale.MINER_INVIS_STATUS.toString()
+ .replaceAll("%status%", player.hasPotionEffect(PotionEffectType.INVISIBILITY) ? C.color("&aEnabled") : C.color("&cDisabled")));
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/kits/type/RougeKit.java b/src/main/java/me/hulipvp/hcf/game/kits/type/RougeKit.java
new file mode 100644
index 0000000..3ce2765
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/kits/type/RougeKit.java
@@ -0,0 +1,113 @@
+package me.hulipvp.hcf.game.kits.type;
+
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.game.kits.Kit;
+import me.hulipvp.hcf.game.player.HCFProfile;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimer;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimerType;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.TimeUtils;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.bukkit.util.Vector;
+
+import java.util.Arrays;
+
+public class RougeKit extends Kit {
+
+ public RougeKit() {
+ super("Rogue", ArmorType.CHAIN, Arrays.asList(new PotionEffect(PotionEffectType.SPEED, Integer.MAX_VALUE, 2, false), new PotionEffect(PotionEffectType.DAMAGE_RESISTANCE, Integer.MAX_VALUE, 1, false)));
+ }
+
+ @EventHandler
+ public void onInteract(PlayerInteractEvent e) {
+ if(!e.getAction().name().contains("RIGHT"))
+ return;
+ if(!Kit.isWearingKit(e.getPlayer(), this.getType()))
+ return;
+ if(!e.hasItem())
+ return;
+ if(e.getItem().getType() != Material.SUGAR && e.getItem().getType() != Material.FEATHER)
+ return;
+
+ PlayerTimerType timerType = e.getItem().getType() == Material.FEATHER ? PlayerTimerType.JUMP_EFFECT : PlayerTimerType.SPEED_EFFECT;
+ PotionEffectType potionType = e.getItem().getType() == Material.FEATHER ? PotionEffectType.JUMP : PotionEffectType.SPEED;
+
+ HCFProfile profile = HCFProfile.getByPlayer(e.getPlayer());
+ PlayerTimer timer = profile.getTimerByType(timerType);
+ if(timer == null) {
+ timer = new PlayerTimer(e.getPlayer(), timerType);
+ timer.add();
+
+ e.getPlayer().removePotionEffect(potionType);
+ e.getPlayer().addPotionEffect(new PotionEffect(potionType, 10 * 20, 4, false));
+
+ new BukkitRunnable() {
+ @Override
+ public void run() {
+ if(!Kit.isWearingKit(e.getPlayer(), getType()))
+ return;
+
+ getEffects().stream()
+ .filter(effect -> effect.getType() == potionType)
+ .forEach(effect -> {
+ e.getPlayer().addPotionEffect(effect, true);
+ });
+ }
+ }.runTaskLater(HCF.getInstance(), 190L);
+
+ int newAmount = e.getItem().getAmount() - 1;
+ if(newAmount == 0)
+ e.getPlayer().setItemInHand(new ItemStack(Material.AIR, 1));
+ else
+ e.getItem().setAmount(newAmount);
+ e.getPlayer().updateInventory();
+ } else {
+ e.setCancelled(true);
+ e.getPlayer().sendMessage(Locale.TIMER_CANNOT_USE.toString().replaceAll("%time%", timer.getFormattedTime().replaceAll("s", "")));
+ }
+ }
+
+ @EventHandler
+ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
+ if(event.getDamager() instanceof Player && event.getEntity() instanceof Player) {
+ Player damager = (Player) event.getDamager();
+ if(!Kit.isWearingKit(damager, this.getType()))
+ return;
+ if(!isBehindPlayer((Player) event.getEntity(), damager))
+ return;
+
+ ItemStack hand = damager.getItemInHand();
+ if(hand != null && hand.getType() == Material.GOLD_SWORD && Math.random() < 0.15) {
+ event.setDamage(TimeUtils.random.nextInt(4));
+
+ Player damaged = (Player) event.getEntity();
+ damager.sendMessage(Locale.ROGUE_BACKSTAB.toString().replaceAll("%backstabbed%", damaged.getName()));
+ damaged.sendMessage(Locale.ROGUE_BACKSTABBED.toString().replaceAll("%backstabber%", damager.getName()));
+
+ damager.setItemInHand(null);
+ damager.playSound(damager.getLocation(), Sound.ITEM_BREAK, 1.0F, 1.0F);
+ damaged.playSound(damager.getLocation(), Sound.ITEM_BREAK, 1.0F, 1.0F);
+ }
+ }
+ }
+
+ private boolean isBehindPlayer(Player player, Player attacker) {
+ Location playerLoc = attacker.getEyeLocation();
+ Location attackerLoc = player.getEyeLocation();
+
+ Vector aVector = playerLoc.toVector().subtract(attackerLoc.toVector()); // Get vector between you and other
+ Vector bVector = attacker.getEyeLocation().getDirection(); // Get direction you are looking at
+
+ return aVector.dot(bVector) > 0;
+ }
+}
diff --git a/src/main/java/me/hulipvp/hcf/game/player/HCFProfile.java b/src/main/java/me/hulipvp/hcf/game/player/HCFProfile.java
new file mode 100644
index 0000000..5690df1
--- /dev/null
+++ b/src/main/java/me/hulipvp/hcf/game/player/HCFProfile.java
@@ -0,0 +1,536 @@
+package me.hulipvp.hcf.game.player;
+
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import lombok.Getter;
+import lombok.Setter;
+import me.hulipvp.hcf.HCF;
+import me.hulipvp.hcf.api.chat.C;
+import me.hulipvp.hcf.game.faction.Claim;
+import me.hulipvp.hcf.game.faction.ClaimPillar;
+import me.hulipvp.hcf.game.faction.Faction;
+import me.hulipvp.hcf.game.faction.type.FactionType;
+import me.hulipvp.hcf.game.faction.type.player.PlayerFaction;
+import me.hulipvp.hcf.game.kits.Kit;
+import me.hulipvp.hcf.game.player.data.ChatMode;
+import me.hulipvp.hcf.game.player.data.ClaimData;
+import me.hulipvp.hcf.game.player.data.Death;
+import me.hulipvp.hcf.game.player.data.Kill;
+import me.hulipvp.hcf.game.player.data.mod.ModMode;
+import me.hulipvp.hcf.game.player.data.setting.HCFSetting;
+import me.hulipvp.hcf.game.player.data.setting.SettingType;
+import me.hulipvp.hcf.game.player.data.statistic.HCFStatistic;
+import me.hulipvp.hcf.game.player.data.statistic.StatisticType;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimer;
+import me.hulipvp.hcf.game.timer.type.player.PlayerTimerType;
+import me.hulipvp.hcf.utils.LocUtils;
+import me.hulipvp.hcf.utils.Locale;
+import me.hulipvp.hcf.utils.item.InvUtils;
+import me.hulipvp.hcf.utils.player.PlayerUtils;
+import org.apache.commons.lang.WordUtils;
+import org.bson.Document;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class HCFProfile {
+
+ @Getter private static final Map profiles = new HashMap<>();
+
+ @Getter private final UUID uuid;
+
+ @Getter @Setter private String name;
+ @Getter @Setter private int lives, balance;
+ @Getter @Setter private long bannedTill, lastRevive;
+ @Getter @Setter private UUID faction;
+
+ @Getter private List kills;
+ @Getter private List deaths;
+ @Getter private List settings;
+ @Getter private List statistics;
+ @Getter private List timers;
+ @Getter private List notes, ignored;
+
+ @Getter private ClaimData claimData;
+
+ @Getter @Setter private Kit currentKit;
+ @Getter @Setter private ModMode modMode;
+ @Getter @Setter private ChatMode chatMode;
+ @Getter @Setter private int streak;
+ @Getter @Setter private boolean bypass, filterEnabled, messagingEnabled, messagingSounds, staffChat;
+ @Getter @Setter private Location mapLocation, stuckLocation;
+ @Getter @Setter private long lastReportTime, lastRequestTime;
+ @Getter @Setter private Player lastMessaged;
+ @Getter @Setter private List filtered;
+ @Getter @Setter private Map> mapPillars;
+
+ public HCFProfile(UUID uuid, boolean cache) {
+ this.uuid = uuid;
+
+ this.kills = new ArrayList<>();
+ this.deaths = new ArrayList<>();
+ this.settings = new ArrayList<>();
+ this.statistics = new ArrayList<>();
+ this.filtered = new ArrayList<>();
+ this.timers = new ArrayList<>();
+ this.notes = new ArrayList<>();
+ this.ignored = new ArrayList<>();
+
+ this.claimData = new ClaimData();
+ this.chatMode = ChatMode.PUBLIC;
+
+ this.messagingEnabled = true;
+ this.messagingSounds = true;
+
+ HCF.getInstance().getBackend().loadProfile(this);
+
+ if(cache)
+ profiles.put(uuid.toString(), this);
+ }
+
+ public HCFProfile(UUID uuid) {
+ this(uuid, true);
+ }
+
+ public Player getPlayer() {
+ return Bukkit.getPlayer(uuid);
+ }
+
+ public void addToBalance(int amount) {
+ balance += amount;
+ }
+
+ public void removeFromBalance(int amount) {
+ balance -= amount;
+ }
+
+ public PlayerFaction getFactionObj() {
+ return faction == null ? null : Faction.getPlayerFaction(faction);
+ }
+
+ public boolean hasFaction() {
+ return getFactionObj() != null;
+ }
+
+ public void addKill(Kill kill) {
+ kills.add(kill);
+ }
+
+ public void addDeath(Death death) {
+ deaths.add(death);
+ }
+
+ public void addTimer(PlayerTimer timer) {
+ timers.add(timer);
+ }
+
+ public void removeTimersByType(PlayerTimerType type) {
+ List timers = this.getTimers().stream()
+ .filter(timer -> timer.getType() == type)
+ .collect(Collectors.toList());
+
+ timers.forEach(timer -> {
+ timer.cancel();
+ this.getTimers().remove(timer);
+ });
+ }
+
+ public PlayerTimer getTimerByType(PlayerTimerType type) {
+ return timers.stream()
+ .filter(timer -> timer.getType() == type)
+ .findFirst()
+ .orElse(null);
+ }
+
+ public void updateTimer(PlayerTimerType type, long time, boolean convert) {
+ timers.stream()
+ .filter(timer -> timer.getType() == type)
+ .forEach(timer -> timer.setCurrentTime(time, convert));
+ }
+
+ public boolean hasTimer(PlayerTimerType type) {
+ return timers.stream()
+ .anyMatch(timer -> timer.getType() == type);
+ }
+
+ public HCFSetting getSetting(SettingType type) {
+ HCFSetting toReturn = settings.stream()
+ .filter(setting -> setting.getType() == type)
+ .findFirst()
+ .orElse(null);
+ if(toReturn == null)
+ settings.add(toReturn = new HCFSetting(type, type.getDefaultValue()));
+
+ return toReturn;
+ }
+
+ public HCFStatistic getStatistic(StatisticType type) {
+ return statistics.stream()
+ .filter(statistic -> statistic.getType() == type)
+ .findFirst()
+ .orElse(null);
+ }
+
+ public void updateStatistic(HCFStatistic statistic) {
+ HCFStatistic found = getStatistic(statistic.getType());
+ if(found == null)
+ return;
+
+ found.setValue(statistic.getValue());
+ }
+
+ public String getChatPrefix() {
+ Player player = getPlayer();
+ String chatDisplay;
+ if(PlayerUtils.hasHook())
+ chatDisplay = PlayerUtils.getRankPrefix(player) + player.getName() + PlayerUtils.getRankSuffix(player);
+ else
+ chatDisplay = player.getName(); // TODO: Hook in with custom core
+
+ return C.color(chatDisplay);
+ }
+
+ public void updateMap(Location location) {
+ mapLocation = location;
+
+ List nearbyFactions = Claim.getNearbyFactions(location, 25);
+ if(nearbyFactions == null || nearbyFactions.isEmpty())
+ return;
+ if(mapPillars == null)
+ mapPillars = new HashMap<>();
+
+ Player player = getPlayer();
+ for(Faction faction : nearbyFactions) {
+ if(faction.getType() == FactionType.WARZONE || faction.getType() == FactionType.ROAD)
+ return;
+
+ if(!mapPillars.containsKey(faction)) {
+ int count = 0;
+ Material material;
+ do {
+ material = ClaimPillar.getRandomMaterial();
+ } while(++count < ClaimPillar.getMaterials().size() && !isValidMapMaterial(material));
+
+ for(Claim claim : faction.getClaims()) {
+ List pillars = mapPillars.getOrDefault(faction, new ArrayList<>());
+
+ for(Location corner : claim.getCorners())
+ pillars.add(new ClaimPillar(corner, material));
+
+ mapPillars.put(faction, pillars);
+
+ pillars.forEach(pillar -> pillar.display(player));
+ }
+
+ player.sendMessage(Locale.COMMAND_FACTION_MAP_FACTION.toString().replaceAll("%faction%", faction.getDisplayFor(player)).replaceAll("%material%", WordUtils.capitalizeFully(material.name().replaceAll("_", " "))));
+ }
+ }
+ }
+
+ public void hideMap() {
+ if(!mapPillars.isEmpty())
+ mapPillars.values().forEach(pillarList -> pillarList.forEach(pillar -> pillar.remove(this.getPlayer())));
+
+ mapPillars.clear();
+ mapPillars = null;
+ mapLocation = null;
+ }
+
+ public boolean isValidMapMaterial(Material material) {
+ if(mapPillars.isEmpty())
+ return true;
+
+ return mapPillars.values().stream()
+ .anyMatch(claimPillars -> claimPillars.stream().anyMatch(claimPillar -> claimPillar.getMaterial() == material));
+ }
+
+ public Long getDeathbanTime() {
+ Player player = getPlayer();
+ if(player != null && (player.isOp() || player.hasPermission("hcf.deathban.bypass")))
+ return 0L;
+
+ String group;
+ if(PlayerUtils.hasHook())
+ group = PlayerUtils.getRankName(player);
+ else
+ group = "default-time"; // TODO: Hook into core
+
+ // TODO: Pre-load all death-ban times into a List using ConfigValues.
+ if(HCF.getInstance().getConfig().contains("deathban.times." + group)) {
+ return HCF.getInstance().getConfig().getLong("deathban.times." + group);
+ } else {
+ return HCF.getInstance().getConfig().getLong("deathban.default-time");
+ }
+ }
+
+ public void reset() {
+ this.kills = new ArrayList<>();
+ this.deaths = new ArrayList<>();
+ this.settings = new ArrayList<>();
+ this.statistics = new ArrayList<>();
+ this.filtered = new ArrayList<>();
+ this.timers = new ArrayList<>();
+ this.notes = new ArrayList<>();
+
+ this.claimData = new ClaimData();
+ this.chatMode = ChatMode.PUBLIC;
+
+ this.lastRevive = 0L;
+ this.bannedTill = 0L;
+ this.balance = 0;
+ this.streak = 0;
+ this.lives = 0;
+
+ for(StatisticType type : StatisticType.values()) {
+ if(this.getStatistic(type) != null)
+ continue;
+
+ HCFStatistic statistic = new HCFStatistic(type, 0);
+ this.getStatistics().add(statistic);
+ }
+
+ for(SettingType type : SettingType.values()) {
+ if(this.getSetting(type) != null)
+ continue;
+
+ this.getSettings().add(new HCFSetting(type, type.getDefaultValue()));
+ }
+ }
+
+ public void save() {
+ HCF.getInstance().getBackend().saveProfile(this);
+ }
+
+ public void load(Document doc) {
+ if(doc.get("name") != null)
+ this.setName(doc.getString("name"));
+ if(doc.get("lives") != null)
+ this.setLives(doc.getInteger("lives"));
+ if(doc.get("balance") != null)
+ this.setBalance(doc.getInteger("balance"));
+ if(doc.get("bannedTill") != null)
+ this.setBannedTill(doc.getLong("bannedTill"));
+
+ if(doc.get("lastRevive") != null)
+ this.setLastRevive(doc.getLong("lastRevive"));
+
+ if(doc.get("faction") != null) {
+ UUID faction = UUID.fromString(doc.getString("faction"));
+ if(Faction.getPlayerFaction(faction) != null)
+ this.setFaction(faction);
+ }
+
+ if(doc.get("notes") != null) {
+ List notes = (ArrayList) doc.get("notes", ArrayList.class);
+ if(notes != null && !notes.isEmpty())
+ this.getNotes().addAll(notes);
+ }
+
+ if(doc.get("ignored") != null) {
+ List ignored = (ArrayList