diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Auction House.iml b/Auction House.iml
index 1287a86..f6807d1 100644
--- a/Auction House.iml
+++ b/Auction House.iml
@@ -30,5 +30,6 @@
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index f2c073f..133024c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -72,5 +72,10 @@
1.12.2-R0.1-SNAPSHOT
provided
+
+ commons-io
+ commons-io
+ 2.4
+
diff --git a/src/main/java/com/massivestats/MassiveStats.java b/src/main/java/com/massivestats/MassiveStats.java
new file mode 100644
index 0000000..8eb26dc
--- /dev/null
+++ b/src/main/java/com/massivestats/MassiveStats.java
@@ -0,0 +1,490 @@
+/*
+ * Copyright 2018 (c) Massive Statistics LLC - All Rights Reserved
+ * This file may only be used in conjunction with the 'MassiveStats' service.
+ */
+
+package com.massivestats;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import javax.net.ssl.HttpsURLConnection;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * MassiveStats collects plugin and server information for plugin authors.
+ * You can learn more at our website: https://www.massivestats.com/
+ *
+ * @version 3.0
+ * @author Sam Jakob Harker, Brianna Hazel O'Keefe
+ */
+@SuppressWarnings("all")
+public class MassiveStats implements Listener {
+
+ /* START: MASSIVESTATS SETTINGS */
+ public static final int CLIENT_VERSION = 0; // v3.0
+ public static final String API_URL = "https://report.massivestats.com/v2/";
+
+ public static final String MASSIVE_UPDATE_PERMISSION = "massivestats.update";
+ /* END: MASSIVESTATS SETTINGS */
+
+ private MassiveStatsUpdateTask task = null;
+ private int pingInterval;
+
+ private MassiveStatsDataResponse lastResponse;
+ private boolean listenerDisabled;
+
+ private final JavaPlugin plugin;
+
+ private Class jsonElement;
+ private Class jsonParser;
+ private Class jsonObject;
+ private Class jsonPrimitive;
+
+ /**
+ * @param plugin The plugin you wish to collect data for.
+ * @author Sam Jakob Harker
+ */
+ public MassiveStats(JavaPlugin plugin){
+ this(plugin, 900); // default value: 900 seconds (= 15 minutes)
+ }
+
+ /**
+ * @param plugin The plugin you wish to collect data for.
+ * @param pingInterval Duration between requests.
+ * @author Sam Jakob Harker
+ */
+ public MassiveStats(JavaPlugin plugin, int pingInterval){
+ try {
+ jsonElement = Class.forName("com.google.gson.JsonElement");
+ jsonParser = Class.forName("com.google.gson.JsonParser");
+ jsonObject = Class.forName("com.google.gson.JsonObject");
+ jsonPrimitive = Class.forName("com.google.gson.JsonPrimitive");
+ }catch(ClassNotFoundException ex){
+ // Gson not included in classpath (so use NMS version)
+ try {
+ jsonElement = Class.forName("net.minecraft.util.com.google.gson.JsonElement");
+ jsonParser = Class.forName("net.minecraft.util.com.google.gson.JsonParser");
+ jsonObject = Class.forName("net.minecraft.util.com.google.gson.JsonObject");
+ jsonPrimitive = Class.forName("net.minecraft.util.com.google.gson.JsonPrimitive");
+ }catch(ClassNotFoundException ignored){
+ Bukkit.getLogger().severe("MassiveStats could not find an instance/version of Gson to use.");
+ this.plugin = null;
+ return;
+ }
+ }
+
+ // Ensure the pingInterval that is set is reasonable.
+ if(pingInterval < 10 || pingInterval > 86400){
+ pingInterval = 900;
+ }
+
+ // Ensure that a plugin instance has been provided.
+ if(plugin == null){
+ throw new IllegalArgumentException("You must provide a plugin for MassiveStats to collect data for!");
+ }
+
+ // Set the ping interval.
+ this.pingInterval = pingInterval;
+ // Set the plugin reference.
+ this.plugin = plugin;
+ // and start sending data to the MassiveStats server immediately.
+ start();
+
+ // Register join/leave events for the plugin
+ Bukkit.getServer().getPluginManager().registerEvents(this, plugin);
+ }
+
+ /**
+ * Gets whether or not the built-in MassiveStats {@link org.bukkit.event.player.PlayerJoinEvent} listener is enabled.
+ * @return Whether or not the MassiveStats listener is enabled.
+ */
+ public boolean isListenerDisabled(){
+ return listenerDisabled;
+ }
+
+ /**
+ * Sets whether or not the built-in MassiveStats {@link org.bukkit.event.player.PlayerJoinEvent} listener is enabled.
+ * @param listenerDisabled Whether or not the MassiveStats listener is enabled.
+ */
+ public void setListenerDisabled(boolean listenerDisabled){
+ this.listenerDisabled = listenerDisabled;
+ }
+
+ /**
+ * Start the MassiveStats reporting timer.
+ * If the timer is already running, this method will do nothing.
+ * @author Sam Jakob Harker
+ */
+ public void start(){
+ if(this.plugin == null){
+ Bukkit.getLogger().severe("MassiveStats could not find an instance/version of Gson to use and thus cannot start.");
+ return;
+ }
+
+ if(task == null){
+ // If the API endpoint URL is invalid, don't start a new task to prevent the user from being spammed.
+ try {
+ new URL(MassiveStats.API_URL);
+ }catch(MalformedURLException ex){
+ getPlugin()
+ .getLogger().warning("You have specified an invalid API endpoint for MassiveStats.");
+ return;
+ }
+
+ task = new MassiveStatsUpdateTask(this);
+ task.runTaskTimerAsynchronously(plugin, 0L, pingInterval * 20L);
+ }
+ }
+
+ /**
+ * Stop the MassiveStats reporting timer.
+ * Requests will no longer be sent to the server - or until {@link #start()} is invoked.
+ * @author Sam Jakob Harker
+ */
+ public void stop(){
+ if(task == null){
+ return;
+ }
+
+ task.cancel();
+ task = null;
+ }
+
+ /**
+ * Sets the duration, in seconds, that MassiveStats should wait before sending another request to the server.
+ * @param pingInterval Duration between requests.
+ * @author Sam Jakob Harker
+ */
+ public void setPingInterval(int pingInterval){
+ this.pingInterval = pingInterval;
+
+ stop();
+ start();
+ }
+
+ /**
+ * Returns the duration, in seconds, that MassiveStats will wait before sending another request to the server.
+ * @return Duration between requests.
+ * @author Sam Jakob Harker
+ */
+ public int getPingInterval(){
+ return pingInterval;
+ }
+
+ /**
+ * Returns the plugin that this MassiveStats instance is collecting data for.
+ * @return MassiveStats instance plugin.
+ * @author Sam Jakob Harker
+ */
+ public JavaPlugin getPlugin(){
+ return plugin;
+ }
+
+ void setLastResponse(MassiveStatsDataResponse lastResponse){
+ this.lastResponse = lastResponse;
+ }
+
+ /**
+ * Returns the contents of the last response from the MassiveStats server.
+ * @return MassiveStats server response.
+ * @author Sam Jakob Harker
+ */
+ public MassiveStatsDataResponse getLastResponse() {
+ return lastResponse;
+ }
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event){
+ // Ensure the listener should be active
+ if(lastResponse == null || listenerDisabled){
+ return;
+ }
+
+ // Of course, only notify the user if the plugin is not up to date.
+ if(lastResponse.isUpToDate()){
+ return;
+ }
+
+ // and only notify operators - or players with the correct permission.
+ if(!event.getPlayer().isOp() && !event.getPlayer().hasPermission(MassiveStats.MASSIVE_UPDATE_PERMISSION)){
+ return;
+ }
+
+ event.getPlayer().sendMessage(lastResponse.getUpdateMessage());
+ }
+
+ Class getJsonElement(){
+ return jsonElement;
+ }
+
+ Class getJsonParser(){
+ return jsonParser;
+ }
+
+ Class getJsonObject(){
+ return jsonObject;
+ }
+
+ Class getJsonPrimitive(){
+ return jsonPrimitive;
+ }
+
+}
+
+class MassiveStatsUpdateTask extends BukkitRunnable {
+
+ private final MassiveStats instance;
+
+ MassiveStatsUpdateTask(MassiveStats requester){
+ instance = requester;
+ }
+
+ @Override
+ @SuppressWarnings("all")
+ public void run(){
+ try {
+ // Generate the request payload and serialize it as JSON.
+ String payload = new MassiveStatsDataRequest(instance).serialize();
+
+ // Then create a new HttpsUrlConnection to the API server and open it.
+ HttpsURLConnection connection = (HttpsURLConnection) new URL(MassiveStats.API_URL).openConnection();
+
+ // Ensure that we don't hang the server with our 'dang shenanigans'.
+ connection.setConnectTimeout(2500);
+ connection.setReadTimeout(3500);
+
+ // Set the all-important request headers before we begin POSTing...
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Accept", "application/json");
+ connection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
+ connection.setRequestProperty("User-Agent", "Massive/" + MassiveStats.CLIENT_VERSION);
+
+ // Open the output stream, write the payload, and then close the stream.
+ connection.setDoOutput(true);
+ DataOutputStream output = new DataOutputStream(connection.getOutputStream());
+ output.writeBytes(payload);
+ output.flush();
+ output.close();
+
+ // Ensure that the server was happy with our data.
+ int responseCode = connection.getResponseCode();
+ if(responseCode != 200){
+ throw new IOException();
+ }
+
+ // Now, read the server's response to our payload...
+ BufferedReader input = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+ StringBuilder response = new StringBuilder();
+
+ // ...line by line.
+ String line;
+ while((line = input.readLine()) != null){
+ response.append(line);
+ }
+ input.close();
+
+ // Now, we parse the JSON object.
+ try {
+ if(response.toString().contains("ERR_DATA_MISSING")){
+ Bukkit.getLogger().severe("MassiveStats has encountered an error for the following plugin: "
+ + instance.getPlugin().getName());
+ instance.stop();
+ return;
+ }
+
+ Object parser = instance.getJsonParser().newInstance();
+
+ // JsonElement
+ Object serverResponseRaw =
+ parser.getClass().getMethod("parse", String.class).invoke(parser, response.toString());
+
+ // JsonObject
+ Object serverResponse = serverResponseRaw.getClass().getMethod("getAsJsonObject", null)
+ .invoke(serverResponseRaw, null);
+
+ Method serverResponseGet = instance.getJsonObject().getMethod("get", String.class);
+
+ Method getAsBoolean =
+ instance.getJsonPrimitive().getMethod("getAsBoolean", null);
+ Method getAsString =
+ instance.getJsonPrimitive().getMethod("getAsString", null);
+
+ if(serverResponseGet.invoke(serverResponse, "upToDate") == null){
+ Bukkit.getLogger().severe("MassiveStats has encountered an error for the following plugin: "
+ + instance.getPlugin().getName());
+ instance.stop();
+ return;
+ }
+
+ if(serverResponseGet.invoke(serverResponse, "notice") != null) {
+ Bukkit.getLogger().severe(
+ (String) getAsString.invoke(serverResponseGet.invoke(serverResponse, "notice"))
+ );
+ instance.stop();
+ return;
+ }
+
+ boolean upToDate = (boolean) getAsBoolean.invoke(serverResponseGet.invoke(serverResponse, "upToDate"), null);
+ String latestVersion = (String) getAsString.invoke(serverResponseGet.invoke(serverResponse, "latestVersion"), null);
+ String updateMessage = ChatColor.translateAlternateColorCodes(
+ '&', (String) getAsString.invoke(serverResponseGet.invoke(serverResponse, "updateMessage"), null)
+ );
+
+ instance.setLastResponse(new MassiveStatsDataResponse(
+ upToDate, latestVersion, updateMessage
+ ));
+
+ }catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
+ instance.getPlugin()
+ .getLogger().warning("MassiveStats returned an invalid response for this plugin.");
+ }
+
+ // Finally, call an event to mark the update.
+ } catch(MalformedURLException ex){
+ instance.getPlugin()
+ .getLogger().warning("You have specified an invalid API endpoint for MassiveStats.");
+ }catch(IOException ex){
+ instance.getPlugin()
+ .getLogger().warning("MassiveStats was unable to communicate with its API endpoint.");
+ }
+ }
+
+}
+
+class MassiveStatsDataRequest {
+
+ private Object jsonObject;
+
+ MassiveStatsDataRequest(MassiveStats requester){
+ try {
+ jsonObject = requester.getJsonObject().newInstance();
+
+ Method add =
+ requester.getJsonObject().newInstance().getClass().getMethod("add", String.class, requester.getJsonElement());
+ Method addPropertyString =
+ requester.getJsonObject().newInstance().getClass().getMethod("addProperty", String.class, String.class);
+ Method addPropertyNumber =
+ requester.getJsonObject().newInstance().getClass().getMethod("addProperty", String.class, Number.class);
+ Method addPropertyBoolean =
+ requester.getJsonObject().newInstance().getClass().getMethod("addProperty", String.class, Boolean.class);
+
+ addPropertyNumber.invoke(jsonObject, "now", System.currentTimeMillis());
+
+ /* PLUGIN DATA */
+ Object pluginObject = jsonObject.getClass().newInstance();
+ addPropertyString.invoke(pluginObject, "name", requester.getPlugin().getDescription().getName());
+ addPropertyString.invoke(pluginObject, "version", requester.getPlugin().getDescription().getVersion());
+ add.invoke(jsonObject, "plugin", pluginObject);
+
+ /* SERVER DATA */
+ Object minecraftServerObject = jsonObject.getClass().newInstance();
+ addPropertyNumber.invoke(minecraftServerObject, "players", Bukkit.getServer().getOnlinePlayers().size());
+ addPropertyBoolean.invoke(minecraftServerObject, "onlineMode", Bukkit.getServer().getOnlineMode());
+ addPropertyString.invoke(minecraftServerObject, "version", Bukkit.getServer().getVersion());
+
+ Object javaServerObject = jsonObject.getClass().newInstance();
+ addPropertyString.invoke(javaServerObject, "version", System.getProperty("java.version"));
+
+ Object osServerObject = jsonObject.getClass().newInstance();
+ addPropertyString.invoke(osServerObject, "name", System.getProperty("os.name"));
+ addPropertyString.invoke(osServerObject, "arch", System.getProperty("os.arch"));
+ addPropertyString.invoke(osServerObject, "version", System.getProperty("os.version"));
+
+ Object hardwareServerObject = jsonObject.getClass().newInstance();
+ addPropertyNumber.invoke(hardwareServerObject, "cores", Runtime.getRuntime().availableProcessors());
+
+ Object serverObject = jsonObject.getClass().newInstance();
+ add.invoke(serverObject, "minecraft", minecraftServerObject);
+ add.invoke(serverObject, "java", javaServerObject);
+ add.invoke(serverObject, "os", osServerObject);
+ add.invoke(serverObject,"hardware", hardwareServerObject);
+
+ add.invoke(jsonObject, "server", serverObject);
+
+ /* MASSIVE DATA */
+ Object massiveObject = jsonObject.getClass().newInstance();
+ addPropertyNumber.invoke(massiveObject, "version", MassiveStats.CLIENT_VERSION);
+ addPropertyNumber.invoke(massiveObject, "pingInterval", requester.getPingInterval());
+
+ //object.add("Massive", massiveObject);
+ add.invoke(jsonObject,"Massive", massiveObject);
+ } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @SuppressWarnings("all")
+ public String serialize(){
+ //return object.toString();
+ try {
+ Method toString = jsonObject.getClass().getMethod("toString", null);
+ return (String) toString.invoke(jsonObject);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+}
+
+@SuppressWarnings("unused")
+final class MassiveStatsDataResponse {
+
+ private final boolean isUpToDate;
+ private final String newVersion;
+ private final String updateMessage;
+
+ MassiveStatsDataResponse(boolean isUpToDate, String newVersion, String updateMessage){
+ this.isUpToDate = isUpToDate;
+
+ if(!isUpToDate) {
+ this.newVersion = newVersion;
+ this.updateMessage = updateMessage;
+ return;
+ }
+
+ this.newVersion = null;
+ this.updateMessage = null;
+ }
+
+ /**
+ * Indicates whether or not this version of the plugin is the latest.
+ * True = This is the latest version of the plugin.
+ * False = There is an update available.
+ * @return Whether or not there is an update available.
+ */
+ public boolean isUpToDate() {
+ return isUpToDate;
+ }
+
+ /**
+ * Gets the name of the latest version. If this is the latest version, it returns null.
+ * @return The name of the latest version.
+ */
+ public String getLatestVersion(){
+ return newVersion;
+ }
+
+ /**
+ * Gets the message to display, convincing the user to update to the new version of the plugin.
+ * @return The update message to display.
+ */
+ public String getUpdateMessage(){
+ return updateMessage;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/shadebyte/auctionhouse/Core.java b/src/main/java/com/shadebyte/auctionhouse/Core.java
index 1dbb55a..b7e9025 100644
--- a/src/main/java/com/shadebyte/auctionhouse/Core.java
+++ b/src/main/java/com/shadebyte/auctionhouse/Core.java
@@ -4,14 +4,21 @@ import org.bukkit.plugin.java.JavaPlugin;
public final class Core extends JavaPlugin {
+ private static Core instance;
+
@Override
public void onEnable() {
// Plugin startup logic
-
+ instance = this;
}
@Override
public void onDisable() {
// Plugin shutdown logic
+ instance = null;
+ }
+
+ public static Core getInstance() {
+ return instance;
}
}
diff --git a/src/main/java/com/shadebyte/auctionhouse/api/AuctionAPI.java b/src/main/java/com/shadebyte/auctionhouse/api/AuctionAPI.java
new file mode 100644
index 0000000..ee8c5c0
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/api/AuctionAPI.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.api;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:48 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class AuctionAPI {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/api/enums/Lang.java b/src/main/java/com/shadebyte/auctionhouse/api/enums/Lang.java
new file mode 100644
index 0000000..c9fdc8f
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/api/enums/Lang.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.api.enums;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:52 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public enum Lang {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/api/enums/Permissions.java b/src/main/java/com/shadebyte/auctionhouse/api/enums/Permissions.java
new file mode 100644
index 0000000..dab0dd5
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/api/enums/Permissions.java
@@ -0,0 +1,22 @@
+package com.shadebyte.auctionhouse.api.enums;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:52 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public enum Permissions {
+
+ BASE("AuctionHouse");
+
+ private String node;
+
+ Permissions(String node) {
+ this.node = node;
+ }
+
+ public String getNode() {
+ return node;
+ }
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/api/enums/Sounds.java b/src/main/java/com/shadebyte/auctionhouse/api/enums/Sounds.java
new file mode 100644
index 0000000..c9e20be
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/api/enums/Sounds.java
@@ -0,0 +1,231 @@
+package com.shadebyte.auctionhouse.api.enums;
+
+import org.bukkit.Sound;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:56 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+
+/**
+ * https://www.spigotmc.org/threads/1-8-to-1-9-sounds.142007/
+ */
+
+public enum Sounds {
+ AMBIENCE_CAVE("AMBIENCE_CAVE", "AMBIENT_CAVE"),
+ AMBIENCE_RAIN("AMBIENCE_RAIN", "WEATHER_RAIN"),
+ AMBIENCE_THUNDER("AMBIENCE_THUNDER", "ENTITY_LIGHTNING_THUNDER"),
+ ANVIL_BREAK("ANVIL_BREAK", "BLOCK_ANVIL_BREAK"),
+ ANVIL_LAND("ANVIL_LAND", "BLOCK_ANVIL_LAND"),
+ ANVIL_USE("ANVIL_USE", "BLOCK_ANVIL_USE"),
+ ARROW_HIT("ARROW_HIT", "ENTITY_ARROW_HIT"),
+ BURP("BURP", "ENTITY_PLAYER_BURP"),
+ CHEST_CLOSE("CHEST_CLOSE", "ENTITY_CHEST_CLOSE"),
+ CHEST_OPEN("CHEST_OPEN", "ENTITY_CHEST_OPEN"),
+ CLICK("CLICK", "UI_BUTTON_CLICK"),
+ DOOR_CLOSE("DOOR_CLOSE", "BLOCK_WOODEN_DOOR_CLOSE"),
+ DOOR_OPEN("DOOR_OPEN", "BLOCK_WOODEN_DOOR_OPEN"),
+ DRINK("DRINK", "ENTITY_GENERIC_DRINK"),
+ EAT("EAT", "ENTITY_GENERIC_EAT"),
+ EXPLODE("EXPLODE", "ENTITY_GENERIC_EXPLODE"),
+ FALL_BIG("FALL_BIG", "ENTITY_GENERIC_BIG_FALL"),
+ FALL_SMALL("FALL_SMALL", "ENTITY_GENERIC_SMALL_FALL"),
+ FIRE("FIRE", "BLOCK_FIRE_AMBIENT"),
+ FIRE_IGNITE("FIRE_IGNITE", "ITEM_FLINTANDSTEEL_USE"),
+ FIZZ("FIZZ", "BLOCK_FIRE_EXTINGUISH"),
+ FUSE("FUSE", "ENTITY_TNT_PRIMED"),
+ GLASS("GLASS", "BLOCK_GLASS_BREAK"),
+ HURT_FLESH("HURT_FLESH", "ENTITY_PLAYER_HURT"),
+ ITEM_BREAK("ITEM_BREAK", "ENTITY_ITEM_BREAK"),
+ ITEM_PICKUP("ITEM_PICKUP", "ENTITY_ITEM_PICKUP"),
+ LAVA("LAVA", "BLOCK_LAVA_AMBIENT"),
+ LAVA_POP("LAVA_POP", "BLOCK_LAVA_POP"),
+ LEVEL_UP("LEVEL_UP", "ENTITY_PLAYER_LEVELUP"),
+ MINECART_BASE("MINECART_BASE", "ENTITY_MINECART_RIDING"),
+ MINECART_INSIDE("MINECART_INSIDE", "ENTITY_MINECART_RIDING"),
+ NOTE_BASS("NOTE_BASS", "BLOCK_NOTE_BASS"),
+ NOTE_PIANO("NOTE_PIANO", "BLOCK_NOTE_HARP"),
+ NOTE_BASS_DRUM("NOTE_BASS_DRUM", "BLOCK_NOTE_BASEDRUM"),
+ NOTE_STICKS("NOTE_STICKS", "BLOCK_NOTE_HAT"),
+ NOTE_BASS_GUITAR("NOTE_BASS_GUITAR", "BLOCK_NOTE_BASS"),
+ NOTE_SNARE_DRUM("NOTE_SNARE_DRUM", "BLOCK_NOTE_SNARE"),
+ NOTE_PLING("NOTE_PLING", "BLOCK_NOTE_PLING"),
+ ORB_PICKUP("ORB_PICKUP", "ENTITY_EXPERIENCE_ORB_PICKUP"),
+ PISTON_EXTEND("PISTON_EXTEND", "BLOCK_PISTON_EXTEND"),
+ PISTON_RETRACT("PISTON_RETRACT", "BLOCK_PISTON_CONTRACT"),
+ PORTAL("PORTAL", "BLOCK_PORTAL_AMBIENT"),
+ PORTAL_TRAVEL("PORTAL_TRAVEL", "BLOCK_PORTAL_TRAVEL"),
+ PORTAL_TRIGGER("PORTAL_TRIGGER", "BLOCK_PORTAL_TRIGGER"),
+ SHOOT_ARROW("SHOOT_ARROW", "ENTITY_ARROW_SHOOT"),
+ SPLASH("SPLASH", "ENTITY_GENERIC_SPLASH"),
+ SPLASH2("SPLASH2", "ENTITY_BOBBER_SPLASH"),
+ STEP_GRASS("STEP_GRASS", "BLOCK_GRASS_STEP"),
+ STEP_GRAVEL("STEP_GRAVEL", "BLOCK_GRAVEL_STEP"),
+ STEP_LADDER("STEP_LADDER", "BLOCK_LADDER_STEP"),
+ STEP_SAND("STEP_SAND", "BLOCK_SAND_STEP"),
+ STEP_SNOW("STEP_SNOW", "BLOCK_SNOW_STEP"),
+ STEP_STONE("STEP_STONE", "BLOCK_STONE_STEP"),
+ STEP_WOOD("STEP_WOOD", "BLOCK_WOOD_STEP"),
+ STEP_WOOL("STEP_WOOL", "BLOCK_CLOTH_STEP"),
+ SWIM("SWIM", "ENTITY_GENERIC_SWIM"),
+ WATER("WATER", "BLOCK_WATER_AMBIENT"),
+ WOOD_CLICK("WOOD_CLICK", "BLOCK_WOOD_BUTTON_CLICK_ON"),
+ BAT_DEATH("BAT_DEATH", "ENTITY_BAT_DEATH"),
+ BAT_HURT("BAT_HURT", "ENTITY_BAT_HURT"),
+ BAT_IDLE("BAT_IDLE", "ENTITY_BAT_AMBIENT"),
+ BAT_LOOP("BAT_LOOP", "ENTITY_BAT_LOOP"),
+ BAT_TAKEOFF("BAT_TAKEOFF", "ENTITY_BAT_TAKEOFF"),
+ BLAZE_BREATH("BLAZE_BREATH", "ENTITY_BLAZE_AMBIENT"),
+ BLAZE_DEATH("BLAZE_DEATH", "ENTITY_BLAZE_DEATH"),
+ BLAZE_HIT("BLAZE_HIT", "ENTITY_BLAZE_HURT"),
+ CAT_HISS("CAT_HISS", "ENTITY_CAT_HISS"),
+ CAT_HIT("CAT_HIT", "ENTITY_CAT_HURT"),
+ CAT_MEOW("CAT_MEOW", "ENTITY_CAT_AMBIENT"),
+ CAT_PURR("CAT_PURR", "ENTITY_CAT_PURR"),
+ CAT_PURREOW("CAT_PURREOW", "ENTITY_CAT_PURREOW"),
+ CHICKEN_IDLE("CHICKEN_IDLE", "ENTITY_CHICKEN_AMBIENT"),
+ CHICKEN_HURT("CHICKEN_HURT", "ENTITY_CHICKEN_HURT"),
+ CHICKEN_EGG_POP("CHICKEN_EGG_POP", "ENTITY_CHICKEN_EGG"),
+ CHICKEN_WALK("CHICKEN_WALK", "ENTITY_CHICKEN_STEP"),
+ COW_IDLE("COW_IDLE", "ENTITY_COW_AMBIENT"),
+ COW_HURT("COW_HURT", "ENTITY_COW_HURT"),
+ COW_WALK("COW_WALK", "ENTITY_COW_STEP"),
+ CREEPER_HISS("CREEPER_HISS", "ENTITY_CREEPER_PRIMED"),
+ CREEPER_DEATH("CREEPER_DEATH", "ENTITY_CREEPER_DEATH"),
+ ENDERDRAGON_DEATH("ENDERDRAGON_DEATH", "ENTITY_ENDERDRAGON_DEATH"),
+ ENDERDRAGON_GROWL("ENDERDRAGON_GROWL", "ENTITY_ENDERDRAGON_GROWL"),
+ ENDERDRAGON_HIT("ENDERDRAGON_HIT", "ENTITY_ENDERDRAGON_HURT"),
+ ENDERDRAGON_WINGS("ENDERDRAGON_WINGS", "ENTITY_ENDERDRAGON_FLAP"),
+ ENDERMAN_DEATH("ENDERMAN_DEATH", "ENTITY_ENDERMEN_DEATH"),
+ ENDERMAN_HIT("ENDERMAN_HIT", "ENTITY_ENDERMEN_HURT"),
+ ENDERMAN_IDLE("ENDERMAN_IDLE", "ENTITY_ENDERMEN_AMBIENT"),
+ ENDERMAN_TELEPORT("ENDERMAN_TELEPORT", "ENTITY_ENDERMEN_TELEPORT"),
+ ENDERMAN_SCREAM("ENDERMAN_SCREAM", "ENTITY_ENDERMEN_SCREAM"),
+ ENDERMAN_STARE("ENDERMAN_STARE", "ENTITY_ENDERMEN_STARE"),
+ GHAST_SCREAM("GHAST_SCREAM", "ENTITY_GHAST_SCREAM"),
+ GHAST_SCREAM2("GHAST_SCREAM2", "ENTITY_GHAST_HURT"),
+ GHAST_CHARGE("GHAST_CHARGE", "ENTITY_GHAST_WARN"),
+ GHAST_DEATH("GHAST_DEATH", "ENTITY_GHAST_DEATH"),
+ GHAST_FIREBALL("GHAST_FIREBALL", "ENTITY_GHAST_SHOOT"),
+ GHAST_MOAN("GHAST_MOAN", "ENTITY_GHAST_AMBIENT"),
+ IRONGOLEM_DEATH("IRONGOLEM_DEATH", "ENTITY_IRONGOLEM_DEATH"),
+ IRONGOLEM_HIT("IRONGOLEM_HIT", "ENTITY_IRONGOLEM_HURT"),
+ IRONGOLEM_THROW("IRONGOLEM_THROW", "ENTITY_IRONGOLEM_ATTACK"),
+ IRONGOLEM_WALK("IRONGOLEM_WALK", "ENTITY_IRONGOLEM_STEP"),
+ MAGMACUBE_WALK("MAGMACUBE_WALK", "ENTITY_MAGMACUBE_SQUISH"),
+ MAGMACUBE_WALK2("MAGMACUBE_WALK2", "ENTITY_MAGMACUBE_SQUISH"),
+ MAGMACUBE_JUMP("MAGMACUBE_JUMP", "ENTITY_MAGMACUBE_JUMP"),
+ PIG_IDLE("PIG_IDLE", "ENTITY_PIG_AMBIENT"),
+ PIG_DEATH("PIG_DEATH", "ENTITY_PIG_DEATH"),
+ PIG_WALK("PIG_WALK", "ENTITY_PIG_STEP"),
+ SHEEP_IDLE("SHEEP_IDLE", "ENTITY_SHEEP_AMBIENT"),
+ SHEEP_SHEAR("SHEEP_SHEAR", "ENTITY_SHEEP_SHEAR"),
+ SHEEP_WALK("SHEEP_WALK", "ENTITY_SHEEP_STEP"),
+ SILVERFISH_HIT("SILVERFISH_HIT", "ENTITY_SILVERFISH_HURT"),
+ SILVERFISH_KILL("SILVERFISH_KILL", "ENTITY_SILVERFISH_DEATH"),
+ SILVERFISH_IDLE("SILVERFISH_IDLE", "ENTITY_SILVERFISH_AMBIENT"),
+ SILVERFISH_WALK("SILVERFISH_WALK", "ENTITY_SILVERFISH_STEP"),
+ SKELETON_IDLE("SKELETON_IDLE", "ENTITY_SKELETON_AMBIENT"),
+ SKELETON_DEATH("SKELETON_DEATH", "ENTITY_SKELETON_DEATH"),
+ SKELETON_HURT("SKELETON_HURT", "ENTITY_SKELETON_HURT"),
+ SKELETON_WALK("SKELETON_WALK", "ENTITY_SKELETON_STEP"),
+ SLIME_ATTACK("SLIME_ATTACK", "ENTITY_SLIME_ATTACK"),
+ SLIME_WALK("SLIME_WALK", "ENTITY_SLIME_JUMP"),
+ SLIME_WALK2("SLIME_WALK2", "ENTITY_SLIME_SQUISH"),
+ SPIDER_IDLE("SPIDER_IDLE", "ENTITY_SPIDER_AMBIENT"),
+ SPIDER_DEATH("SPIDER_DEATH", "ENTITY_SPIDER_DEATH"),
+ SPIDER_WALK("SPIDER_WALK", "ENTITY_SPIDER_STEP"),
+ WITHER_DEATH("WITHER_DEATH", "ENTITY_WITHER_DEATH"),
+ WITHER_HURT("WITHER_HURT", "ENTITY_WITHER_HURT"),
+ WITHER_IDLE("WITHER_IDLE", "ENTITY_WITHER_AMBIENT"),
+ WITHER_SHOOT("WITHER_SHOOT", "ENTITY_WITHER_SHOOT"),
+ WITHER_SPAWN("WITHER_SPAWN", "ENTITY_WITHER_SPAWN"),
+ WOLF_BARK("WOLF_BARK", "ENTITY_WOLF_AMBIENT"),
+ WOLF_DEATH("WOLF_DEATH", "ENTITY_WOLF_DEATH"),
+ WOLF_GROWL("WOLF_GROWL", "ENTITY_WOLF_GROWL"),
+ WOLF_HOWL("WOLF_HOWL", "ENTITY_WOLF_HOWL"),
+ WOLF_HURT("WOLF_HURT", "ENTITY_WOLF_HURT"),
+ WOLF_PANT("WOLF_PANT", "ENTITY_WOLF_PANT"),
+ WOLF_SHAKE("WOLF_SHAKE", "ENTITY_WOLF_SHAKE"),
+ WOLF_WALK("WOLF_WALK", "ENTITY_WOLF_STEP"),
+ WOLF_WHINE("WOLF_WHINE", "ENTITY_WOLF_WHINE"),
+ ZOMBIE_METAL("ZOMBIE_METAL", "ENTITY_ZOMBIE_ATTACK_IRON_DOOR"),
+ ZOMBIE_WOOD("ZOMBIE_WOOD", "ENTITY_ZOMBIE_ATTACK_DOOR_WOOD"),
+ ZOMBIE_WOODBREAK("ZOMBIE_WOODBREAK", "ENTITY_ZOMBIE_BREAK_DOOR_WOOD"),
+ ZOMBIE_IDLE("ZOMBIE_IDLE", "ENTITY_ZOMBIE_AMBIENT"),
+ ZOMBIE_DEATH("ZOMBIE_DEATH", "ENTITY_ZOMBIE_DEATH"),
+ ZOMBIE_HURT("ZOMBIE_HURT", "ENTITY_ZOMBIE_HURT"),
+ ZOMBIE_INFECT("ZOMBIE_INFECT", "ENTITY_ZOMBIE_INFECT"),
+ ZOMBIE_UNFECT("ZOMBIE_UNFECT", "ENTITY_ZOMBIE_VILLAGER_CONVERTED"),
+ ZOMBIE_REMEDY("ZOMBIE_REMEDY", "ENTITY_ZOMBIE_VILLAGER_CURE"),
+ ZOMBIE_WALK("ZOMBIE_WALK", "ENTITY_ZOMBIE_STEP"),
+ ZOMBIE_PIG_IDLE("ZOMBIE_PIG_IDLE", "ENTITY_ZOMBIE_PIG_AMBIENT"),
+ ZOMBIE_PIG_ANGRY("ZOMBIE_PIG_ANGRY", "ENTITY_ZOMBIE_PIG_ANGRY"),
+ ZOMBIE_PIG_DEATH("ZOMBIE_PIG_DEATH", "ENTITY_ZOMBIE_PIG_DEATH"),
+ ZOMBIE_PIG_HURT("ZOMBIE_PIG_HURT", "ENTITY_ZOMBIE_PIG_HURT"),
+ DIG_WOOL("DIG_WOOL", "BLOCK_CLOTH_BREAK"),
+ DIG_GRASS("DIG_GRASS", "BLOCK_GRASS_BREAK"),
+ DIG_GRAVEL("DIG_GRAVEL", "BLOCK_GRAVEL_BREAK"),
+ DIG_SAND("DIG_SAND", "BLOCK_SAND_BREAK"),
+ DIG_SNOW("DIG_SNOW", "BLOCK_SNOW_BREAK"),
+ DIG_STONE("DIG_STONE", "BLOCK_STONE_BREAK"),
+ DIG_WOOD("DIG_WOOD", "BLOCK_WOOD_BREAK"),
+ FIREWORK_BLAST("FIREWORK_BLAST", "ENTITY_FIREWORK_BLAST"),
+ FIREWORK_BLAST2("FIREWORK_BLAST2", "ENTITY_FIREWORK_BLAST_FAR"),
+ FIREWORK_LARGE_BLAST("FIREWORK_LARGE_BLAST", "ENTITY_FIREWORK_LARGE_BLAST"),
+ FIREWORK_LARGE_BLAST2("FIREWORK_LARGE_BLAST2", "ENTITY_FIREWORK_LARGE_BLAST_FAR"),
+ FIREWORK_TWINKLE("FIREWORK_TWINKLE", "ENTITY_FIREWORK_TWINKLE"),
+ FIREWORK_TWINKLE2("FIREWORK_TWINKLE2", "ENTITY_FIREWORK_TWINKLE_FAR"),
+ FIREWORK_LAUNCH("FIREWORK_LAUNCH", "ENTITY_FIREWORK_LAUNCH"),
+ SUCCESSFUL_HIT("SUCCESSFUL_HIT", "ENTITY_PLAYER_ATTACK_STRONG"),
+ HORSE_ANGRY("HORSE_ANGRY", "ENTITY_HORSE_ANGRY"),
+ HORSE_ARMOR("HORSE_ARMOR", "ENTITY_HORSE_ARMOR"),
+ HORSE_BREATHE("HORSE_BREATHE", "ENTITY_HORSE_BREATHE"),
+ HORSE_DEATH("HORSE_DEATH", "ENTITY_HORSE_DEATH"),
+ HORSE_GALLOP("HORSE_GALLOP", "ENTITY_HORSE_GALLOP"),
+ HORSE_HIT("HORSE_HIT", "ENTITY_HORSE_HURT"),
+ HORSE_IDLE("HORSE_IDLE", "ENTITY_HORSE_AMBIENT"),
+ HORSE_JUMP("HORSE_JUMP", "ENTITY_HORSE_JUMP"),
+ HORSE_LAND("HORSE_LAND", "ENTITY_HORSE_LAND"),
+ HORSE_SADDLE("HORSE_SADDLE", "ENTITY_HORSE_SADDLE"),
+ HORSE_SOFT("HORSE_SOFT", "ENTITY_HORSE_STEP"),
+ HORSE_WOOD("HORSE_WOOD", "ENTITY_HORSE_STEP_WOOD"),
+ DONKEY_ANGRY("DONKEY_ANGRY", "ENTITY_DONKEY_ANGRY"),
+ DONKEY_DEATH("DONKEY_DEATH", "ENTITY_DONKEY_DEATH"),
+ DONKEY_HIT("DONKEY_HIT", "ENTITY_DONKEY_HURT"),
+ DONKEY_IDLE("DONKEY_IDLE", "ENTITY_DONKEY_AMBIENT"),
+ HORSE_SKELETON_DEATH("HORSE_SKELETON_DEATH", "ENTITY_SKELETON_HORSE_DEATH"),
+ HORSE_SKELETON_HIT("HORSE_SKELETON_HIT", "ENTITY_SKELETON_HORSE_HURT"),
+ HORSE_SKELETON_IDLE("HORSE_SKELETON_IDLE", "ENTITY_SKELETON_HORSE_AMBIENT"),
+ HORSE_ZOMBIE_DEATH("HORSE_ZOMBIE_DEATH", "ENTITY_ZOMBIE_HORSE_DEATH"),
+ HORSE_ZOMBIE_HIT("HORSE_ZOMBIE_HIT", "ENTITY_ZOMBIE_HORSE_HURT"),
+ HORSE_ZOMBIE_IDLE("HORSE_ZOMBIE_IDLE", "ENTITY_ZOMBIE_HORSE_AMBIENT"),
+ VILLAGER_DEATH("VILLAGER_DEATH", "ENTITY_VILLAGER_DEATH"),
+ VILLAGER_HAGGLE("VILLAGER_HAGGLE", "ENTITY_VILLAGER_TRADING"),
+ VILLAGER_HIT("VILLAGER_HIT", "ENTITY_VILLAGER_HURT"),
+ VILLAGER_IDLE("VILLAGER_IDLE", "ENTITY_VILLAGER_AMBIENT"),
+ VILLAGER_NO("VILLAGER_NO", "ENTITY_VILLAGER_NO"),
+ VILLAGER_YES("VILLAGER_YES", "ENTITY_VILLAGER_YES");
+
+ private String pre19sound;
+ private String post19sound;
+ private Sound resolvedSound = null;
+
+ Sounds(String pre19sound, String post19sound) {
+ this.pre19sound = pre19sound;
+ this.post19sound = post19sound;
+ }
+
+ public Sound bukkitSound() {
+ if (resolvedSound != null) return resolvedSound;
+
+ try {
+ return resolvedSound = Sound.valueOf(post19sound);
+ } catch (IllegalArgumentException e) {
+ //Try 1.8 sound
+ return resolvedSound = Sound.valueOf(pre19sound);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/shadebyte/auctionhouse/api/enums/Version.java b/src/main/java/com/shadebyte/auctionhouse/api/enums/Version.java
new file mode 100644
index 0000000..1e309f4
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/api/enums/Version.java
@@ -0,0 +1,121 @@
+package com.shadebyte.auctionhouse.api.enums;
+
+import org.bukkit.Bukkit;
+
+//Created by Kicjow for crazy crates
+public enum Version {
+
+ TOO_OLD(-1),
+ v1_7_R1(171), v1_7_R2(172), v1_7_R3(173), v1_7_R4(174),
+ v1_8_R1(181), v1_8_R2(182), v1_8_R3(183),
+ v1_9_R1(191), v1_9_R2(192),
+ v1_10_R1(1101),
+ v1_11_R1(1111),
+ v1_12_R1(1121),
+ TOO_NEW(-2);
+
+ private static Version latest;
+ private Integer versionInteger;
+ public static Version currentVersion;
+
+ Version(int versionInteger) {
+ this.versionInteger = versionInteger;
+ }
+
+ /**
+ *
+ * @return Get the server's Minecraft version.
+ */
+ public static Version getCurrentVersion() {
+ if(currentVersion == null) {
+ String ver = Bukkit.getServer().getClass().getPackage().getName();
+ int v = Integer.parseInt(ver.substring(ver.lastIndexOf('.') + 1).replaceAll("_", "").replaceAll("R", "").replaceAll("v", ""));
+ for(Version version : values()) {
+ if(version.getCurrentVersionInteger() == v) {
+ currentVersion = version;
+ break;
+ }
+ }
+ if(v > Version.getLatestVersion().getCurrentVersionInteger()) {
+ currentVersion = Version.getLatestVersion();
+ }
+ if(currentVersion == null) {
+ currentVersion = Version.TOO_NEW;
+ }
+ }
+ return currentVersion;
+ }
+
+ /**
+ *
+ * @return The server's minecraft version as an integer.
+ */
+ public Integer getCurrentVersionInteger() {
+ return this.versionInteger;
+ }
+
+ /**
+ * Get the latest version allowed by the Version class.
+ * @return The latest version.
+ */
+ public static Version getLatestVersion() {
+ if(latest == null) {
+ Version v = Version.TOO_OLD;
+ for(Version version : values()) {
+ if(version.comparedTo(v) == 1) {
+ v = version;
+ }
+ }
+ return v;
+ }else {
+ return latest;
+ }
+ }
+
+ /**
+ * This checks if the current version is older, newer, or is the checked version.
+ * @param version The version you are checking.
+ * @return -1 if older, 0 if the same, and 1 if newer.
+ */
+ public Integer comparedTo(Version version) {
+ int resault = -1;
+ int current = this.getCurrentVersionInteger();
+ int check = version.getCurrentVersionInteger();
+ if(current > check || check == -2) {// check is newer then current
+ resault = 1;
+ }else if(current == check) {// check is the same as current
+ resault = 0;
+ }else if(current < check || check == -1) {// check is older then current
+ resault = -1;
+ }
+ return resault;
+ }
+
+ /**
+ * Checks to see if the current version is newer then the checked version.
+ * @param version The version you are checking.
+ * @return True if newer then the checked version and false if the same or older.
+ */
+ public Boolean isNewer(Version version) {
+ return this.versionInteger > version.versionInteger || this.versionInteger == -2;
+ }
+
+ /**
+ * Checks to see if the current version is the same as the checked version.
+ * @param version The version you are checking.
+ * @return True if both the current and checked version is the same and false if otherwise.
+ */
+ public Boolean isSame(Version version) {
+ return this.versionInteger.equals(version.versionInteger);
+ }
+
+ /**
+ * Checks to see if the current version is older then the checked version.
+ * @param version The version you are checking.
+ * @return True if older then the checked version and false if the same or newer.
+ */
+ public Boolean isOlder(Version version) {
+ return this.versionInteger < version.versionInteger || this.versionInteger == -1;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/shadebyte/auctionhouse/api/event/AuctionCancelEvent.java b/src/main/java/com/shadebyte/auctionhouse/api/event/AuctionCancelEvent.java
new file mode 100644
index 0000000..5980f38
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/api/event/AuctionCancelEvent.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.api.event;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:55 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class AuctionCancelEvent {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/api/event/AuctionEndEvent.java b/src/main/java/com/shadebyte/auctionhouse/api/event/AuctionEndEvent.java
new file mode 100644
index 0000000..d4910fc
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/api/event/AuctionEndEvent.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.api.event;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:54 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class AuctionEndEvent {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/api/event/AuctionStartEvent.java b/src/main/java/com/shadebyte/auctionhouse/api/event/AuctionStartEvent.java
new file mode 100644
index 0000000..93b2622
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/api/event/AuctionStartEvent.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.api.event;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:54 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class AuctionStartEvent {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/auction/AuctionItem.java b/src/main/java/com/shadebyte/auctionhouse/auction/AuctionItem.java
new file mode 100644
index 0000000..2431524
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/auction/AuctionItem.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.auction;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:49 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class AuctionItem {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/auction/AuctionPlayer.java b/src/main/java/com/shadebyte/auctionhouse/auction/AuctionPlayer.java
new file mode 100644
index 0000000..94e32e3
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/auction/AuctionPlayer.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.auction;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:49 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class AuctionPlayer {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/cmds/CommandManager.java b/src/main/java/com/shadebyte/auctionhouse/cmds/CommandManager.java
new file mode 100644
index 0000000..113f167
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/cmds/CommandManager.java
@@ -0,0 +1,99 @@
+package com.shadebyte.auctionhouse.cmds;
+
+import com.shadebyte.auctionhouse.Core;
+import com.shadebyte.auctionhouse.api.enums.Permissions;
+import com.shadebyte.auctionhouse.util.Debugger;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:50 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class CommandManager implements CommandExecutor {
+
+ private List commands = new ArrayList<>();
+
+ public CommandManager() {
+ }
+
+ public final String main = "auctionhouse";
+
+ public final String expired = "expired";
+ public final String help = "help";
+ public final String listed = "listed";
+ public final String reload = "reload";
+ public final String sell = "sell";
+
+ public void initialize() {
+ Core.getInstance().getCommand(main).setExecutor(this);
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+
+ if (!sender.hasPermission(Permissions.BASE.getNode())) {
+ //sender.sendMessage(Core.getInstance().getSettings().getPrefix() + Core.getInstance().getLocale().getMessage(Lang.NO_PERMISSION.getNode()));
+ return true;
+ }
+
+ //Main command text
+ if (command.getName().equalsIgnoreCase(main)) {
+ if (args.length == 0) {
+ //OPEN
+ return true;
+ }
+
+ //Handle Sub commands
+ SubCommand target = this.getSubcommand(args[0]);
+
+ if (target == null) {
+ //sender.sendMessage(Core.getInstance().getSettings().getPrefix() + Core.getInstance().getLocale().getMessage(Lang.INVALID_SUBCOMMAND.getNode()));
+ return true;
+ }
+
+ List list = new ArrayList<>();
+ list.addAll(Arrays.asList(args));
+ list.remove(0);
+
+ try {
+ target.onCommand(sender, args);
+ } catch (Exception e) {
+ Debugger.report(e);
+ }
+ }
+
+ return true;
+ }
+
+ private SubCommand getSubcommand(String name) {
+ Iterator subcommands = this.commands.iterator();
+ while (subcommands.hasNext()) {
+ SubCommand sc = subcommands.next();
+
+ if (sc.name().equalsIgnoreCase(name)) {
+ return sc;
+ }
+
+ String[] aliases;
+ int length = (aliases = sc.aliases()).length;
+
+ for (int var5 = 0; var5 < length; ++var5) {
+ String alias = aliases[var5];
+ if (name.equalsIgnoreCase(alias)) {
+ return sc;
+ }
+
+ }
+ }
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/shadebyte/auctionhouse/cmds/SubCommand.java b/src/main/java/com/shadebyte/auctionhouse/cmds/SubCommand.java
new file mode 100644
index 0000000..89ddbe5
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/cmds/SubCommand.java
@@ -0,0 +1,26 @@
+package com.shadebyte.auctionhouse.cmds;
+
+import org.bukkit.command.CommandSender;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:50 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public abstract class SubCommand {
+
+ /*
+ /command args[++]
+ */
+
+ public SubCommand() {}
+
+ public abstract void onCommand(CommandSender sender, String[] args);
+
+ public abstract String name();
+
+ public abstract String info();
+
+ public abstract String[] aliases();
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/ExpiredCommand.java b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/ExpiredCommand.java
new file mode 100644
index 0000000..4ec7215
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/ExpiredCommand.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.cmds.subcmds;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:51 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class ExpiredCommand {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/HelpCommand.java b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/HelpCommand.java
new file mode 100644
index 0000000..2423a38
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/HelpCommand.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.cmds.subcmds;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:51 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class HelpCommand {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/ListedCommand.java b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/ListedCommand.java
new file mode 100644
index 0000000..42fe686
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/ListedCommand.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.cmds.subcmds;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:51 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class ListedCommand {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/ReloadCommand.java b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/ReloadCommand.java
new file mode 100644
index 0000000..21e437f
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/ReloadCommand.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.cmds.subcmds;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:51 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class ReloadCommand {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/SellCommand.java b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/SellCommand.java
new file mode 100644
index 0000000..66cea42
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/cmds/subcmds/SellCommand.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.cmds.subcmds;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:50 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class SellCommand {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/inventory/AGUI.java b/src/main/java/com/shadebyte/auctionhouse/inventory/AGUI.java
new file mode 100644
index 0000000..07112cc
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/inventory/AGUI.java
@@ -0,0 +1,11 @@
+package com.shadebyte.auctionhouse.inventory;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:54 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public interface AGUI {
+
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/AuctionGUI.java b/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/AuctionGUI.java
new file mode 100644
index 0000000..431aeaa
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/AuctionGUI.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.inventory.inventories;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:56 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class AuctionGUI {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/ConfirmationGUI.java b/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/ConfirmationGUI.java
new file mode 100644
index 0000000..4669832
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/ConfirmationGUI.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.inventory.inventories;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:56 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class ConfirmationGUI {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/ExpiredGUI.java b/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/ExpiredGUI.java
new file mode 100644
index 0000000..74000f3
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/ExpiredGUI.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.inventory.inventories;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:56 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class ExpiredGUI {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/ListingsGUI.java b/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/ListingsGUI.java
new file mode 100644
index 0000000..dd4cd83
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/inventory/inventories/ListingsGUI.java
@@ -0,0 +1,10 @@
+package com.shadebyte.auctionhouse.inventory.inventories;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:56 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class ListingsGUI {
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/util/ConfigWrapper.java b/src/main/java/com/shadebyte/auctionhouse/util/ConfigWrapper.java
new file mode 100644
index 0000000..b962c72
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/util/ConfigWrapper.java
@@ -0,0 +1,74 @@
+package com.shadebyte.auctionhouse.util;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:59 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.logging.Level;
+
+/*
+ Made by @Clip
+ */
+
+public class ConfigWrapper {
+
+ private final JavaPlugin plugin;
+ private FileConfiguration config;
+ private File configFile;
+ private final String folderName, fileName;
+
+ public ConfigWrapper(final JavaPlugin instance, final String folderName, final String fileName) {
+ this.plugin = instance;
+ this.folderName = folderName;
+ this.fileName = fileName;
+ }
+
+ public void createNewFile(final String message, final String header) {
+ reloadConfig();
+ saveConfig();
+ loadConfig(header);
+
+ if (message != null) {
+ plugin.getLogger().info(message);
+ }
+ }
+
+ public FileConfiguration getConfig() {
+ if (config == null) {
+ reloadConfig();
+ }
+ return config;
+ }
+
+ public void loadConfig(final String header) {
+ config.options().header(header);
+ config.options().copyDefaults(true);
+ saveConfig();
+ }
+
+ public void reloadConfig() {
+ if (configFile == null) {
+ configFile = new File(plugin.getDataFolder() + folderName, fileName);
+ }
+ config = YamlConfiguration.loadConfiguration(configFile);
+ }
+
+ public void saveConfig() {
+ if (config == null || configFile == null) {
+ return;
+ }
+ try {
+ getConfig().save(configFile);
+ } catch (final IOException ex) {
+ plugin.getLogger().log(Level.SEVERE, "Could not save config to " + configFile, ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/shadebyte/auctionhouse/util/Debugger.java b/src/main/java/com/shadebyte/auctionhouse/util/Debugger.java
new file mode 100644
index 0000000..d3bb229
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/util/Debugger.java
@@ -0,0 +1,29 @@
+package com.shadebyte.auctionhouse.util;
+
+import com.shadebyte.auctionhouse.Core;
+import org.bukkit.Bukkit;
+
+import static org.bukkit.ChatColor.translateAlternateColorCodes;
+
+/**
+ * The current file has been created by Kiran Hart
+ * Date Created: 7/6/2018
+ * Time Created: 11:59 AM
+ * Usage of any code found within this class is prohibited unless given explicit permission otherwise.
+ */
+public class Debugger {
+
+ public static void report(Exception e) {
+ if (debugEnabled()) {
+ Bukkit.getConsoleSender().sendMessage(translateAlternateColorCodes('&', "&b================================================================"));
+ Bukkit.getConsoleSender().sendMessage(translateAlternateColorCodes('&', "&eAuction House has ran into an error, report this to the author."));
+ Bukkit.getConsoleSender().sendMessage(translateAlternateColorCodes('&', "&b----------------------------------------------------------------"));
+ e.printStackTrace();
+ Bukkit.getConsoleSender().sendMessage(translateAlternateColorCodes('&', "&b================================================================"));
+ }
+ }
+
+ private static boolean debugEnabled() {
+ return Core.getInstance().getConfig().getBoolean("debugger");
+ }
+}
diff --git a/src/main/java/com/shadebyte/auctionhouse/util/Locale.java b/src/main/java/com/shadebyte/auctionhouse/util/Locale.java
new file mode 100644
index 0000000..abfc4f0
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/util/Locale.java
@@ -0,0 +1,364 @@
+package com.shadebyte.auctionhouse.util;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import org.apache.commons.io.IOUtils;
+import org.bukkit.ChatColor;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import java.io.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * Assists in the creation of multiple localizations and languages,
+ * as well as the generation of default .lang files
+ *
+ * @author Parker Hawke - 2008Choco
+ */
+public class Locale {
+
+ private static JavaPlugin plugin;
+ private static final List LOCALES = Lists.newArrayList();
+
+ private static final Pattern NODE_PATTERN = Pattern.compile("(\\w+(?:\\.\\w+)*)\\s*=\\s*\"(.*)\"");
+ private static final String FILE_EXTENSION = ".lang";
+ private static File localeFolder;
+
+ private static String defaultLocale;
+
+ private final Map nodes = new HashMap<>();
+
+ private final File file;
+ private final String name, region;
+
+ private Locale(String name, String region) {
+ if (plugin == null)
+ throw new IllegalStateException("Cannot generate locales without first initializing the class (Locale#init(JavaPlugin))");
+
+ this.name = name.toLowerCase();
+ this.region = region.toUpperCase();
+
+ String fileName = name + "_" + region + FILE_EXTENSION;
+ this.file = new File(localeFolder, fileName);
+
+ if (this.reloadMessages()) return;
+
+ plugin.getLogger().info("Loaded locale " + fileName);
+ }
+
+ /**
+ * Get the name of the language that this locale is based on.
+ * (i.e. "en" for English, or "fr" for French)
+ *
+ * @return the name of the language
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Get the name of the region that this locale is from.
+ * (i.e. "US" for United States or "CA" for Canada)
+ *
+ * @return the name of the region
+ */
+ public String getRegion() {
+ return region;
+ }
+
+ /**
+ * Return the entire locale tag (i.e. "en_US")
+ *
+ * @return the language tag
+ */
+ public String getLanguageTag() {
+ return name + "_" + region;
+ }
+
+ /**
+ * Get the file that represents this locale
+ *
+ * @return the locale file (.lang)
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * Get a message set for a specific node
+ *
+ * @param node the node to get
+ * @return the message for the specified node
+ */
+ public String getMessage(String node) {
+ return ChatColor.translateAlternateColorCodes('&', this.getMessageOrDefault(node, node));
+ }
+
+ /**
+ * Get a message set for a specific node and replace its params with a supplied arguments.
+ *
+ * @param node the node to get
+ * @param args the replacement arguments
+ * @return the message for the specified node
+ */
+ public String getMessage(String node, Object... args) {
+ String message = getMessage(node);
+ for (Object arg : args) {
+ message = message.replaceFirst("%.*?%", arg.toString());
+ }
+ return message;
+ }
+
+ /**
+ * Get a message set for a specific node
+ *
+ * @param node the node to get
+ * @param defaultValue the default value given that a value for the node was not found
+ * @return the message for the specified node. Default if none found
+ */
+ public String getMessageOrDefault(String node, String defaultValue) {
+ return this.nodes.getOrDefault(node, defaultValue);
+ }
+
+ /**
+ * Get the key-value map of nodes to messages
+ *
+ * @return node-message map
+ */
+ public Map getMessageNodeMap() {
+ return ImmutableMap.copyOf(nodes);
+ }
+
+ /**
+ * Clear the previous message cache and load new messages directly from file
+ *
+ * @return reload messages from file
+ */
+ public boolean reloadMessages() {
+ if (!this.file.exists()) {
+ plugin.getLogger().warning("Could not find file for locale " + this.name);
+ return false;
+ }
+
+ this.nodes.clear(); // Clear previous data (if any)
+
+ try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
+ String line;
+ for (int lineNumber = 0; (line = reader.readLine()) != null; lineNumber++) {
+ if (line.isEmpty() || line.startsWith("#") /* Comment */) continue;
+
+ Matcher matcher = NODE_PATTERN.matcher(line);
+ if (!matcher.find()) {
+ System.err.println("Invalid locale syntax at (line=" + lineNumber + ")");
+ continue;
+ }
+
+ nodes.put(matcher.group(1), matcher.group(2));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Initialize the locale class to generate information and search for localizations.
+ * This must be called before any other methods in the Locale class can be invoked.
+ * Note that this will also call {@link #searchForLocales()}, so there is no need to
+ * invoke it for yourself after the initialization
+ *
+ * @param plugin the plugin instance
+ */
+ public static void init(JavaPlugin plugin) {
+ Locale.plugin = plugin;
+
+ if (localeFolder == null) {
+ localeFolder = new File(plugin.getDataFolder(), "locales/");
+ }
+
+ localeFolder.mkdirs();
+ Locale.searchForLocales();
+ }
+
+ /**
+ * Find all .lang file locales under the "locales" folder
+ */
+ public static void searchForLocales() {
+ if (!localeFolder.exists()) localeFolder.mkdirs();
+
+ for (File file : localeFolder.listFiles()) {
+ String name = file.getName();
+ if (!name.endsWith(".lang")) continue;
+
+ String fileName = name.substring(0, name.lastIndexOf('.'));
+ String[] localeValues = fileName.split("_");
+
+ if (localeValues.length != 2) continue;
+ if (localeExists(localeValues[0] + "_" + localeValues[1])) continue;
+
+ LOCALES.add(new Locale(localeValues[0], localeValues[1]));
+ plugin.getLogger().info("Found and loaded locale \"" + fileName + "\"");
+ }
+ }
+
+ /**
+ * Get a locale by its entire proper name (i.e. "en_US")
+ *
+ * @param name the full name of the locale
+ * @return locale of the specified name
+ */
+ public static Locale getLocale(String name) {
+ for (Locale locale : LOCALES)
+ if (locale.getLanguageTag().equalsIgnoreCase(name)) return locale;
+ return null;
+ }
+
+ /**
+ * Get a locale from the cache by its name (i.e. "en" from "en_US")
+ *
+ * @param name the name of the language
+ * @return locale of the specified language. Null if not cached
+ */
+ public static Locale getLocaleByName(String name) {
+ for (Locale locale : LOCALES)
+ if (locale.getName().equalsIgnoreCase(name)) return locale;
+ return null;
+ }
+
+ /**
+ * Get a locale from the cache by its region (i.e. "US" from "en_US")
+ *
+ * @param region the name of the region
+ * @return locale of the specified region. Null if not cached
+ */
+ public static Locale getLocaleByRegion(String region) {
+ for (Locale locale : LOCALES)
+ if (locale.getRegion().equalsIgnoreCase(region)) return locale;
+ return null;
+ }
+
+ /**
+ * Check whether a locale exists and is registered or not
+ *
+ * @param name the whole language tag (i.e. "en_US")
+ * @return true if it exists
+ */
+ public static boolean localeExists(String name) {
+ for (Locale locale : LOCALES)
+ if (locale.getLanguageTag().equals(name)) return true;
+ return false;
+ }
+
+ /**
+ * Get an immutable list of all currently loaded locales
+ *
+ * @return list of all locales
+ */
+ public static List getLocales() {
+ return ImmutableList.copyOf(LOCALES);
+ }
+
+ /**
+ * Save a default locale file from the project source directory, to the locale folder
+ *
+ * @param path the path to the file to save
+ * @param fileName the name of the file to save
+ * @return true if the operation was successful, false otherwise
+ */
+ public static boolean saveDefaultLocale(String path, String fileName) {
+ if (!localeFolder.exists()) localeFolder.mkdirs();
+
+ if (!fileName.endsWith(FILE_EXTENSION))
+ fileName = (fileName.lastIndexOf(".") == -1 ? fileName : fileName.substring(0, fileName.lastIndexOf('.'))) + FILE_EXTENSION;
+
+ File destinationFile = new File(localeFolder, fileName);
+ if (destinationFile.exists()) {
+ return compareFiles(plugin.getResource(fileName), destinationFile);
+ }
+
+ try (OutputStream outputStream = new FileOutputStream(destinationFile)) {
+ IOUtils.copy(plugin.getResource(fileName), outputStream);
+
+ fileName = fileName.substring(0, fileName.lastIndexOf('.'));
+ String[] localeValues = fileName.split("_");
+
+ if (localeValues.length != 2) return false;
+
+ LOCALES.add(new Locale(localeValues[0], localeValues[1]));
+ if (defaultLocale == null) defaultLocale = fileName;
+
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Save a default locale file from the project source directory, to the locale folder
+ *
+ * @param fileName the name of the file to save
+ * @return true if the operation was successful, false otherwise
+ */
+ public static boolean saveDefaultLocale(String fileName) {
+ return saveDefaultLocale("", fileName);
+ }
+
+ /**
+ * Clear all current locale data
+ */
+ public static void clearLocaleData() {
+ for (Locale locale : LOCALES)
+ locale.nodes.clear();
+ LOCALES.clear();
+ }
+
+ // Write new changes to existing files, if any at all
+ private static boolean compareFiles(InputStream defaultFile, File existingFile) {
+ // Look for default
+ if (defaultFile == null) {
+ defaultFile = plugin.getResource(defaultLocale != null ? defaultLocale : "en_US");
+ if (defaultFile == null) return false; // No default at all
+ }
+
+ boolean changed = false;
+
+ List defaultLines, existingLines;
+ try (BufferedReader defaultReader = new BufferedReader(new InputStreamReader(defaultFile));
+ BufferedReader existingReader = new BufferedReader(new FileReader(existingFile));
+ BufferedWriter writer = new BufferedWriter(new FileWriter(existingFile, true))) {
+ defaultLines = defaultReader.lines().collect(Collectors.toList());
+ existingLines = existingReader.lines().map(s -> s.split("\\s*=")[0]).collect(Collectors.toList());
+
+ for (String defaultValue : defaultLines) {
+ if (defaultValue.isEmpty() || defaultValue.startsWith("#")) continue;
+
+ String key = defaultValue.split("\\s*=")[0];
+
+ if (!existingLines.contains(key)) {
+ if (!changed) {
+ writer.newLine();
+ writer.newLine();
+ writer.write("# New messages for " + plugin.getName() + " v" + plugin.getDescription().getVersion());
+ }
+
+ writer.newLine();
+ writer.write(defaultValue);
+
+ changed = true;
+ }
+ }
+ } catch (IOException e) {
+ return false;
+ }
+
+ return changed;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/shadebyte/auctionhouse/util/NBTEditor.java b/src/main/java/com/shadebyte/auctionhouse/util/NBTEditor.java
new file mode 100644
index 0000000..6cb2ba4
--- /dev/null
+++ b/src/main/java/com/shadebyte/auctionhouse/util/NBTEditor.java
@@ -0,0 +1,460 @@
+package com.shadebyte.auctionhouse.util;
+
+import com.google.common.primitives.Primitives;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.block.Block;
+import org.bukkit.entity.Entity;
+import org.bukkit.inventory.ItemStack;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Sets/Gets NBT tags from ItemStacks
+ *
+ * @author BananaPuncher714
+ * @version 5.0
+ */
+public class NBTEditor {
+ private static HashMap> classCache;
+ private static HashMap methodCache;
+ private static HashMap, Constructor>> constructorCache;
+ private static HashMap, Class>> NBTClasses;
+ private static HashMap, Field> NBTTagFieldCache;
+ private static Field NBTListData;
+ private static Field NBTCompoundMap;
+ private static String version;
+
+ static {
+ version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
+
+ classCache = new HashMap>();
+ try {
+ classCache.put("NBTBase", Class.forName("net.minecraft.server." + version + "." + "NBTBase"));
+ classCache.put("NBTTagCompound", Class.forName("net.minecraft.server." + version + "." + "NBTTagCompound"));
+ classCache.put("NBTTagList", Class.forName("net.minecraft.server." + version + "." + "NBTTagList"));
+ classCache.put("NBTBase", Class.forName("net.minecraft.server." + version + "." + "NBTBase"));
+
+ classCache.put("ItemStack", Class.forName("net.minecraft.server." + version + "." + "ItemStack"));
+ classCache.put("CraftItemStack", Class.forName("org.bukkit.craftbukkit." + version + ".inventory." + "CraftItemStack"));
+
+ classCache.put("Entity", Class.forName("net.minecraft.server." + version + "." + "Entity"));
+ classCache.put("CraftEntity", Class.forName("org.bukkit.craftbukkit." + version + ".entity." + "CraftEntity"));
+ classCache.put("EntityLiving", Class.forName("net.minecraft.server." + version + "." + "EntityLiving"));
+
+ classCache.put("CraftWorld", Class.forName("org.bukkit.craftbukkit." + version + "." + "CraftWorld"));
+ classCache.put("CraftBlockState", Class.forName("org.bukkit.craftbukkit." + version + ".block." + "CraftBlockState"));
+ classCache.put("BlockPosition", Class.forName("net.minecraft.server." + version + "." + "BlockPosition"));
+ classCache.put("TileEntity", Class.forName("net.minecraft.server." + version + "." + "TileEntity"));
+ classCache.put("World", Class.forName("net.minecraft.server." + version + "." + "World"));
+
+ classCache.put("TileEntitySkull", Class.forName("net.minecraft.server." + version + "." + "TileEntitySkull"));
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ NBTClasses = new HashMap, Class>>();
+ try {
+ NBTClasses.put(Byte.class, Class.forName("net.minecraft.server." + version + "." + "NBTTagByte"));
+ NBTClasses.put(String.class, Class.forName("net.minecraft.server." + version + "." + "NBTTagString"));
+ NBTClasses.put(Double.class, Class.forName("net.minecraft.server." + version + "." + "NBTTagDouble"));
+ NBTClasses.put(Integer.class, Class.forName("net.minecraft.server." + version + "." + "NBTTagInt"));
+ NBTClasses.put(Long.class, Class.forName("net.minecraft.server." + version + "." + "NBTTagLong"));
+ NBTClasses.put(Short.class, Class.forName("net.minecraft.server." + version + "." + "NBTTagShort"));
+ NBTClasses.put(Float.class, Class.forName("net.minecraft.server." + version + "." + "NBTTagFloat"));
+ NBTClasses.put(Class.forName("[B"), Class.forName("net.minecraft.server." + version + "." + "NBTTagByteArray"));
+ NBTClasses.put(Class.forName("[I"), Class.forName("net.minecraft.server." + version + "." + "NBTTagIntArray"));
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ methodCache = new HashMap();
+ try {
+ methodCache.put("get", getNMSClass("NBTTagCompound").getMethod("get", String.class));
+ methodCache.put("set", getNMSClass("NBTTagCompound").getMethod("set", String.class, getNMSClass("NBTBase")));
+ methodCache.put("hasKey", getNMSClass("NBTTagCompound").getMethod("hasKey", String.class));
+ methodCache.put("setIndex", getNMSClass("NBTTagList").getMethod("a", int.class, getNMSClass("NBTBase")));
+ methodCache.put("add", getNMSClass("NBTTagList").getMethod("add", getNMSClass("NBTBase")));
+
+ methodCache.put("hasTag", getNMSClass("ItemStack").getMethod("hasTag"));
+ methodCache.put("getTag", getNMSClass("ItemStack").getMethod("getTag"));
+ methodCache.put("setTag", getNMSClass("ItemStack").getMethod("setTag", getNMSClass("NBTTagCompound")));
+ methodCache.put("asNMSCopy", getNMSClass("CraftItemStack").getMethod("asNMSCopy", ItemStack.class));
+ methodCache.put("asBukkitCopy", getNMSClass("CraftItemStack").getMethod("asBukkitCopy", getNMSClass("ItemStack")));
+
+ methodCache.put("getEntityHandle", getNMSClass("CraftEntity").getMethod("getHandle"));
+ methodCache.put("getEntityTag", getNMSClass("Entity").getMethod("c", getNMSClass("NBTTagCompound")));
+ methodCache.put("setEntityTag", getNMSClass("Entity").getMethod("f", getNMSClass("NBTTagCompound")));
+
+ if (version.contains("1_12")) {
+ methodCache.put("setTileTag", getNMSClass("TileEntity").getMethod("load", getNMSClass("NBTTagCompound")));
+ } else {
+ methodCache.put("setTileTag", getNMSClass("TileEntity").getMethod("a", getNMSClass("NBTTagCompound")));
+ }
+ methodCache.put("getTileEntity", getNMSClass("World").getMethod("getTileEntity", getNMSClass("BlockPosition")));
+ methodCache.put("getWorldHandle", getNMSClass("CraftWorld").getMethod("getHandle"));
+
+ //methodCache.put( "setGameProfile", getNMSClass( "TileEntitySkull" ).getMethod( "setGameProfile", GameProfile.class ) );
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ methodCache.put("getTileTag", getNMSClass("TileEntity").getMethod("save", getNMSClass("NBTTagCompound")));
+ } catch (NoSuchMethodException exception) {
+ try {
+ methodCache.put("getTileTag", getNMSClass("TileEntity").getMethod("b", getNMSClass("NBTTagCompound")));
+ } catch (Exception exception2) {
+ exception2.printStackTrace();
+ }
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ }
+
+ constructorCache = new HashMap, Constructor>>();
+ try {
+ constructorCache.put(getNBTTag(Byte.class), getNBTTag(Byte.class).getConstructor(byte.class));
+ constructorCache.put(getNBTTag(String.class), getNBTTag(String.class).getConstructor(String.class));
+ constructorCache.put(getNBTTag(Double.class), getNBTTag(Double.class).getConstructor(double.class));
+ constructorCache.put(getNBTTag(Integer.class), getNBTTag(Integer.class).getConstructor(int.class));
+ constructorCache.put(getNBTTag(Long.class), getNBTTag(Long.class).getConstructor(long.class));
+ constructorCache.put(getNBTTag(Float.class), getNBTTag(Float.class).getConstructor(float.class));
+ constructorCache.put(getNBTTag(Short.class), getNBTTag(Short.class).getConstructor(short.class));
+ constructorCache.put(getNBTTag(Class.forName("[B")), getNBTTag(Class.forName("[B")).getConstructor(Class.forName("[B")));
+ constructorCache.put(getNBTTag(Class.forName("[I")), getNBTTag(Class.forName("[I")).getConstructor(Class.forName("[I")));
+
+ constructorCache.put(getNMSClass("BlockPosition"), getNMSClass("BlockPosition").getConstructor(int.class, int.class, int.class));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ NBTTagFieldCache = new HashMap, Field>();
+ try {
+ for (Class> clazz : NBTClasses.values()) {
+ Field data = clazz.getDeclaredField("data");
+ data.setAccessible(true);
+ NBTTagFieldCache.put(clazz, data);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ NBTListData = getNMSClass("NBTTagList").getDeclaredField("list");
+ NBTListData.setAccessible(true);
+ NBTCompoundMap = getNMSClass("NBTTagCompound").getDeclaredField("map");
+ NBTCompoundMap.setAccessible(true);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static Class> getPrimitiveClass(Class> clazz) {
+ return Primitives.unwrap(clazz);
+ }
+
+ public static Class> getNBTTag(Class> primitiveType) {
+ if (NBTClasses.containsKey(primitiveType))
+ return NBTClasses.get(primitiveType);
+ return primitiveType;
+ }
+
+ public static Object getNBTVar(Object object) {
+ if (object == null) return null;
+ Class> clazz = object.getClass();
+ try {
+ if (NBTTagFieldCache.containsKey(clazz)) {
+ return NBTTagFieldCache.get(clazz).get(object);
+ }
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ }
+ return null;
+ }
+
+ public static Method getMethod(String name) {
+ return methodCache.containsKey(name) ? methodCache.get(name) : null;
+ }
+
+ public static Constructor> getConstructor(Class> clazz) {
+ return constructorCache.containsKey(clazz) ? constructorCache.get(clazz) : null;
+ }
+
+ public static Class> getNMSClass(String name) {
+ if (classCache.containsKey(name)) {
+ return classCache.get(name);
+ }
+
+ try {
+ return Class.forName("net.minecraft.server." + version + "." + name);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static String getMatch(String string, String regex) {
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(string);
+ if (matcher.find()) {
+ return matcher.group(1);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Gets an NBT tag in a given item with the specified keys
+ *
+ * @param item The itemstack to get the keys from
+ * @param key The keys to fetch; an integer after a key value indicates that it should get the nth place of
+ * the previous compound because it is a list;
+ * @return The item represented by the keys, and an integer if it is showing how long a list is.
+ */
+ public static Object getItemTag(ItemStack item, Object... keys) {
+ try {
+ Object stack = null;
+ stack = getMethod("asNMSCopy").invoke(null, item);
+
+ Object tag = null;
+
+ if (getMethod("hasTag").invoke(stack).equals(true)) {
+ tag = getMethod("getTag").invoke(stack);
+ } else {
+ tag = getNMSClass("NBTTagCompound").newInstance();
+ }
+
+ return getTag(tag, keys);
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Sets an NBT tag in an item with the provided keys and value
+ *
+ * @param item The itemstack to set
+ * @param key The keys to set, String for NBTCompound, int or null for an NBTTagList
+ * @param value The value to set
+ * @return A new ItemStack with the updated NBT tags
+ */
+ public static ItemStack setItemTag(ItemStack item, Object value, Object... keys) {
+ try {
+ Object stack = getMethod("asNMSCopy").invoke(null, item);
+
+ Object tag = null;
+
+ if (getMethod("hasTag").invoke(stack).equals(true)) {
+ tag = getMethod("getTag").invoke(stack);
+ } else {
+ tag = getNMSClass("NBTTagCompound").newInstance();
+ }
+
+ setTag(tag, value, keys);
+ getMethod("setTag").invoke(stack, tag);
+ return (ItemStack) getMethod("asBukkitCopy").invoke(null, stack);
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Gets an NBT tag in a given entity with the specified keys
+ *
+ * @param block The entity to get the keys from
+ * @param key The keys to fetch; an integer after a key value indicates that it should get the nth place of
+ * the previous compound because it is a list;
+ * @return The item represented by the keys, and an integer if it is showing how long a list is.
+ */
+ public static Object getEntityTag(Entity entity, Object... keys) {
+ try {
+ Object NMSEntity = getMethod("getEntityHandle").invoke(entity);
+
+ Object tag = getNMSClass("NBTTagCompound").newInstance();
+
+ getMethod("getEntityTag").invoke(NMSEntity, tag);
+
+ return getTag(tag, keys);
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Sets an NBT tag in an entity with the provided keys and value
+ *
+ * @param item The entity to set
+ * @param key The keys to set, String for NBTCompound, int or null for an NBTTagList
+ * @param value The value to set
+ * @return A new ItemStack with the updated NBT tags
+ */
+ public static void setEntityTag(Entity entity, Object value, Object... keys) {
+ try {
+ Object NMSEntity = getMethod("getEntityHandle").invoke(entity);
+
+ Object tag = getNMSClass("NBTTagCompound").newInstance();
+
+ getMethod("getEntityTag").invoke(NMSEntity, tag);
+
+ setTag(tag, value, keys);
+
+ getMethod("setEntityTag").invoke(NMSEntity, tag);
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ return;
+ }
+ }
+
+ /**
+ * Gets an NBT tag in a given block with the specified keys
+ *
+ * @param block The block to get the keys from
+ * @param key The keys to fetch; an integer after a key value indicates that it should get the nth place of
+ * the previous compound because it is a list;
+ * @return The item represented by the keys, and an integer if it is showing how long a list is.
+ */
+ public static Object getBlockTag(Block block, Object... keys) {
+ try {
+ if (!getNMSClass("CraftBlockState").isInstance(block.getState())) {
+ return null;
+ }
+
+ Object tileEntity = getMethod("getTileEntity").invoke(block.getState());
+
+ Object tag = getMethod("getTileTag").invoke(tileEntity, getNMSClass("NBTTagCompound").newInstance());
+
+ return getTag(tag, keys);
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Sets an NBT tag in an block with the provided keys and value
+ *
+ * @param item The block to set
+ * @param key The keys to set, String for NBTCompound, int or null for an NBTTagList
+ * @param value The value to set
+ * @return A new ItemStack with the updated NBT tags
+ */
+ public static void setBlockTag(Block block, Object value, Object... keys) {
+ try {
+ Location location = block.getLocation();
+
+ Object blockPosition = getConstructor(getNMSClass("BlockPosition")).newInstance(location.getBlockX(), location.getBlockY(), location.getBlockZ());
+
+ Object nmsWorld = getMethod("getWorldHandle").invoke(location.getWorld());
+
+ Object tileEntity = getMethod("getTileEntity").invoke(nmsWorld, blockPosition);
+
+ Object tag = getMethod("getTileTag").invoke(tileEntity, getNMSClass("NBTTagCompound").newInstance());
+
+ setTag(tag, value, keys);
+
+ getMethod("setTileTag").invoke(tileEntity, tag);
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ return;
+ }
+ }
+
+ private static void setTag(Object tag, Object value, Object... keys) throws Exception {
+ Object notCompound = getConstructor(getNBTTag(value.getClass())).newInstance(value);
+
+ Object compound = tag;
+ for (int index = 0; index < keys.length; index++) {
+ Object key = keys[index];
+ if (index + 1 == keys.length) {
+ if (key == null) {
+ getMethod("add").invoke(compound, notCompound);
+ } else if (key instanceof Integer) {
+ getMethod("setIndex").invoke(compound, (int) key, notCompound);
+ } else {
+ getMethod("set").invoke(compound, (String) key, notCompound);
+ }
+ break;
+ }
+ Object oldCompound = compound;
+ if (key instanceof Integer) {
+ compound = ((List>) NBTListData.get(compound)).get((int) key);
+ } else if (key != null) {
+ compound = getMethod("get").invoke(compound, (String) key);
+ }
+ if (compound == null || key == null) {
+ if (keys[index + 1] == null || keys[index + 1] instanceof Integer) {
+ compound = getNMSClass("NBTTagList").newInstance();
+ } else {
+ compound = getNMSClass("NBTTagCompound").newInstance();
+ }
+ if (oldCompound.getClass().getSimpleName().equals("NBTTagList")) {
+ getMethod("add").invoke(oldCompound, compound);
+ } else {
+ getMethod("set").invoke(oldCompound, (String) key, compound);
+ }
+ }
+ }
+ }
+
+ private static Object getTag(Object tag, Object... keys) throws Exception {
+ if (keys.length == 0) return getTags(tag);
+
+ Object notCompound = tag;
+
+ for (Object key : keys) {
+ if (notCompound == null) return null;
+ if (getNMSClass("NBTTagCompound").isInstance(notCompound)) {
+ notCompound = getMethod("get").invoke(notCompound, (String) key);
+ } else if (getNMSClass("NBTTagList").isInstance(notCompound)) {
+ notCompound = ((List>) NBTListData.get(notCompound)).get((int) key);
+ } else {
+ return getNBTVar(notCompound);
+ }
+ }
+ if (notCompound == null) return null;
+ if (getNMSClass("NBTTagList").isInstance(notCompound)) {
+ return getTags(notCompound);
+ } else if (getNMSClass("NBTTagCompound").isInstance(notCompound)) {
+ return getTags(notCompound);
+ } else {
+ return getNBTVar(notCompound);
+ }
+ }
+
+ private static Object getTags(Object tag) {
+ HashMap