diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000..349e88b
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.externalToolBuilders/Faucet build.xml [Builder].launch b/.externalToolBuilders/Faucet build.xml [Builder].launch
new file mode 100644
index 0000000..e69f5f4
--- /dev/null
+++ b/.externalToolBuilders/Faucet build.xml [Builder].launch
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ae3c172
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/.project b/.project
new file mode 100644
index 0000000..f241d61
--- /dev/null
+++ b/.project
@@ -0,0 +1,27 @@
+
+
+ Faucet
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.eclipse.ui.externaltools.ExternalToolBuilder
+ full,incremental,
+
+
+ LaunchConfigHandle
+ <project>/.externalToolBuilders/Faucet build.xml [Builder].launch
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/manifest.mf b/manifest.mf
new file mode 100644
index 0000000..c8b23f2
--- /dev/null
+++ b/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Class-Path: ../lib/CommandManager.jar ../lib/ChatAPI.jar ../lib/ChestAPI.jar
+
diff --git a/plugin.yml b/plugin.yml
new file mode 100644
index 0000000..5e3833f
--- /dev/null
+++ b/plugin.yml
@@ -0,0 +1,5 @@
+name: Faucet
+version: 1.0.0
+authors: [pepich1851]
+main: com.redstoner.Main
+softdepend: [Vault]
\ No newline at end of file
diff --git a/src/com/redstoner/annotations/AutoRegisterListener.java b/src/com/redstoner/annotations/AutoRegisterListener.java
new file mode 100644
index 0000000..eb1c7c0
--- /dev/null
+++ b/src/com/redstoner/annotations/AutoRegisterListener.java
@@ -0,0 +1,14 @@
+package com.redstoner.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** The auto register annotation, to be put onto Classes that implement listener when you are too lazy to register the events yourself.
+ *
+ * @author Pepich */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AutoRegisterListener
+{}
diff --git a/src/com/redstoner/annotations/Commands.java b/src/com/redstoner/annotations/Commands.java
new file mode 100644
index 0000000..6b42c82
--- /dev/null
+++ b/src/com/redstoner/annotations/Commands.java
@@ -0,0 +1,15 @@
+package com.redstoner.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.redstoner.misc.CommandHolder;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Commands
+{
+ CommandHolder value();
+}
diff --git a/src/com/redstoner/annotations/Depends.java b/src/com/redstoner/annotations/Depends.java
new file mode 100644
index 0000000..063a1f6
--- /dev/null
+++ b/src/com/redstoner/annotations/Depends.java
@@ -0,0 +1,13 @@
+package com.redstoner.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Depends
+{
+ String[] value();
+}
diff --git a/src/com/redstoner/annotations/SoftDepends.java b/src/com/redstoner/annotations/SoftDepends.java
new file mode 100644
index 0000000..06c6b0f
--- /dev/null
+++ b/src/com/redstoner/annotations/SoftDepends.java
@@ -0,0 +1,13 @@
+package com.redstoner.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SoftDepends
+{
+ String[] value();
+}
diff --git a/src/com/redstoner/annotations/Version.java b/src/com/redstoner/annotations/Version.java
new file mode 100644
index 0000000..e700292
--- /dev/null
+++ b/src/com/redstoner/annotations/Version.java
@@ -0,0 +1,33 @@
+package com.redstoner.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** The Version annotation, to be applied to all Classes that are part of the project.
+ *
+ * @author Pepich */
+@Target(ElementType.TYPE)
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Version
+{
+ /** The major indicator of the version. Will be used for compatibility detection.
+ *
+ * @return the major version as an int */
+ int major();
+
+ int minor();
+
+ int revision();
+
+ /** The compatibility part of the version number. Will be used for compatibility detection.
+ * Set to -1 if it is supposed to be always compatible.
+ * Defaults to 1.
+ *
+ * @return the smallest compatible version as an int. */
+ int compatible() default 1;
+
+}
diff --git a/src/com/redstoner/exceptions/NonSaveableConfigException.java b/src/com/redstoner/exceptions/NonSaveableConfigException.java
new file mode 100644
index 0000000..df33bff
--- /dev/null
+++ b/src/com/redstoner/exceptions/NonSaveableConfigException.java
@@ -0,0 +1,9 @@
+package com.redstoner.exceptions;
+
+public class NonSaveableConfigException extends Exception {
+ private static final long serialVersionUID = -7271481973389455510L;
+
+ public NonSaveableConfigException() {
+ super("This config does not support saving!");
+ }
+}
diff --git a/src/com/redstoner/faucet/Faucet.java b/src/com/redstoner/faucet/Faucet.java
new file mode 100644
index 0000000..d276fe9
--- /dev/null
+++ b/src/com/redstoner/faucet/Faucet.java
@@ -0,0 +1,70 @@
+package com.redstoner.faucet;
+
+import java.util.HashMap;
+
+import org.bukkit.plugin.java.JavaPlugin;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.mysql.MysqlHandler;
+import com.redstoner.modules.Module;
+
+import net.nemez.chatapi.ChatAPI;
+
+/** Main class. Duh.
+ *
+ * @author Pepich */
+@Version(major = 4, minor = 0, revision = 0, compatible = -1)
+public class Faucet extends JavaPlugin
+{
+ public static JavaPlugin plugin;
+ public static HashMap modules = new HashMap<>();
+ public static HashMap states = new HashMap<>();
+
+ private final ClassLoader parentLoader;
+
+ public Faucet()
+ {
+ parentLoader = Faucet.class.getClassLoader();
+ }
+
+ @Override
+ public void onEnable()
+ {
+ plugin = this;
+ ChatAPI.initialize(this);
+ // Configger.init();
+ MysqlHandler.init();
+ }
+
+ @Override
+ public void onDisable()
+ {}
+
+ @Command(hook = "load")
+ public static boolean loadModule()
+ {
+ return false;
+ }
+
+ @Command(hook = "tap")
+ public static boolean loadBarrel()
+ {
+ return false;
+ }
+
+ public static boolean isEnabled(Module module)
+ {
+ return states.get(module);
+ }
+
+ public static void disable(String name)
+ {
+ Faucet.disable(modules.get(name));
+ }
+
+ public static void disable(Module module)
+ {
+
+ }
+}
diff --git a/src/com/redstoner/misc/BroadcastFilter.java b/src/com/redstoner/misc/BroadcastFilter.java
new file mode 100644
index 0000000..b5b887c
--- /dev/null
+++ b/src/com/redstoner/misc/BroadcastFilter.java
@@ -0,0 +1,11 @@
+package com.redstoner.misc;
+
+import org.bukkit.command.CommandSender;
+
+/** Classes implementing this interface can be used to define a filter for the Utils.broadcast method for sending a message to more than one, but less than all users.
+ *
+ * @author Pepich */
+public interface BroadcastFilter
+{
+ public boolean sendTo(CommandSender recipient);
+}
diff --git a/src/com/redstoner/misc/CommandHolder.java b/src/com/redstoner/misc/CommandHolder.java
new file mode 100644
index 0000000..4b3511f
--- /dev/null
+++ b/src/com/redstoner/misc/CommandHolder.java
@@ -0,0 +1,10 @@
+package com.redstoner.misc;
+
+/** @author Pepich */
+public enum CommandHolder
+{
+ Stream,
+ File,
+ String,
+ None
+}
diff --git a/src/com/redstoner/misc/JsonManager.java b/src/com/redstoner/misc/JsonManager.java
new file mode 100644
index 0000000..7f5c703
--- /dev/null
+++ b/src/com/redstoner/misc/JsonManager.java
@@ -0,0 +1,144 @@
+package com.redstoner.misc;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+/** This class provides simple JSON handling, like storing and loading from and to files.
+ *
+ * @author Pepich */
+public class JsonManager
+{
+ private JsonManager()
+ {}
+
+ /** Loads a JSONObject from a file.
+ *
+ * @param source the file to load from.
+ * @return the JSONObject or null if the source does not contain a valid JSONObject. */
+ public static JSONObject getObject(File source)
+ {
+ if (!source.exists())
+ return null;
+ JSONParser parser = new JSONParser();
+ try
+ {
+ FileReader reader = new FileReader(source);
+ Object rawObject = parser.parse(reader);
+ reader.close();
+ JSONObject jsonObject = (JSONObject) rawObject;
+ return jsonObject;
+ }
+ catch (IOException | ParseException e)
+ {}
+ return null;
+ }
+
+ /** Saves a JSONObject to a file. Will create the necessary FileStructure like folders and the file itself.
+ * Note that this operation will be run on a different thread and you do not need to take care of that yourself.
+ *
+ * @param object the JSONObject to save.
+ * @param destination the file to write to. */
+ public static void save(JSONObject object, File destination)
+ {
+ Thread t = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ saveSync(object, destination);
+ }
+ });
+ t.start();
+ }
+
+ /** Saves a JSONObject to a file. Will create the necessary FileStructure like folders and the file itself.
+ * Note that this operation will be run on the same thread that you are calling it from!
+ *
+ * @param object the JSONObject to save.
+ * @param destination the file to write to. */
+ public static void saveSync(JSONObject object, File destination)
+ {
+ if (destination.exists())
+ destination.delete();
+ else if (!destination.getParentFile().exists())
+ destination.getParentFile().mkdirs();
+ try
+ {
+ destination.createNewFile();
+ FileWriter writer = new FileWriter(destination);
+ object.writeJSONString(writer);
+ writer.flush();
+ writer.close();
+ }
+ catch (IOException e)
+ {}
+ }
+
+ /** Loads a JSONArray from a file.
+ *
+ * @param source the file to load from.
+ * @return the JSONArray or null if the source does not contain a valid JSONArray. */
+ public static JSONArray getArray(File source)
+ {
+ if (!source.exists())
+ return null;
+ JSONParser parser = new JSONParser();
+ try
+ {
+ Object rawObject = parser.parse(new FileReader(source));
+ JSONArray jsonArray = (JSONArray) rawObject;
+ return jsonArray;
+ }
+ catch (IOException | ParseException e)
+ {}
+ return null;
+ }
+
+ /** Saves a JSONArray to a file. Will create the necessary FileStructure like folders and the file itself.
+ * Note that this operation will be run on a different thread and you do not need to take care of that yourself.
+ *
+ * @param object the JSONArray to save.
+ * @param destination the file to write to. */
+ public static void save(JSONArray array, File destination)
+ {
+ Thread t = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ saveSync(array, destination);
+ }
+ });
+ t.start();
+ }
+
+ /** Saves a JSONArray to a file. Will create the necessary FileStructure like folders and the file itself.
+ * Note that this operation will be run on the same thread that you are calling it from!
+ *
+ * @param object the JSONArray to save.
+ * @param destination the file to write to. */
+ public static void saveSync(JSONArray array, File destination)
+ {
+ if (destination.exists())
+ destination.delete();
+ else if (!destination.getParentFile().exists())
+ destination.getParentFile().mkdirs();
+ try
+ {
+ destination.createNewFile();
+ FileWriter writer = new FileWriter(destination);
+ array.writeJSONString(writer);
+ writer.flush();
+ writer.close();
+ }
+ catch (IOException e)
+ {}
+ }
+}
diff --git a/src/com/redstoner/misc/Utils.java b/src/com/redstoner/misc/Utils.java
new file mode 100644
index 0000000..352dbce
--- /dev/null
+++ b/src/com/redstoner/misc/Utils.java
@@ -0,0 +1,129 @@
+package com.redstoner.misc;
+
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+/** The utils class containing utility functions. Those include but are not limited to sending formatted messages, broadcasts and more.
+ *
+ * @author Pepich */
+public final class Utils
+{
+ /** The @SimpleDateFormat used for getting the current date. */
+ public static SimpleDateFormat dateFormat = new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]");
+
+ /** Hidden constructor. Do not instantiate UTILS classes! :) */
+ private Utils()
+ {}
+
+ /** This method broadcasts a message to all players and console that are allowed by the filter. Set the filter to NULL to broadcast to everyone.
+ * If you want to, you can set a message that will be logged to console. Set to null to not log anything.
+ * You can still allow console in the filter to log the original message.
+ *
+ * @param prefix The prefix for the message. Set to NULL to let it auto generate.
+ * @param message the message to be sent around
+ * @param filter the BroadcastFilter to be applied.
+ * Write a class implementing the interface and pass it to this method, the "sendTo()" method will be called for each recipient.
+ * @param logmessage the log message to appear in console. Set to null to not log this (you can still log the original message by returning true in the filter).
+ * @return the amount of people that received the message. */
+ public static int broadcast(String prefix, String message, BroadcastFilter filter)
+ {
+ if (prefix == null)
+ prefix = "§8[§2" + getCaller() + "§8]: ";
+ if (filter == null)
+ {
+ for (Player p : Bukkit.getOnlinePlayers())
+ p.sendMessage(prefix + message);
+ Bukkit.getConsoleSender().sendMessage(prefix + message);
+ return Bukkit.getOnlinePlayers().size() + 1;
+ }
+ else
+ {
+ int count = 0;
+ for (Player p : Bukkit.getOnlinePlayers())
+ if (filter.sendTo(p))
+ {
+ p.sendMessage(prefix + message);
+ count++;
+ }
+ if (filter.sendTo(Bukkit.getConsoleSender()))
+ {
+ Bukkit.getConsoleSender().sendMessage(prefix + message);
+ count++;
+ }
+ return count;
+ }
+ }
+
+ /** This method will find the next parent caller and return their class name, omitting package names.
+ *
+ * @return the Name of the calling class. */
+ private static final String getCaller()
+ {
+ StackTraceElement[] stackTrace = (new Exception()).getStackTrace();
+ String classname = "Utils";
+ for (int i = 0; classname.equals("Utils"); i++)
+ {
+ classname = stackTrace[i].getClassName().replaceAll(".*\\.", "");
+ }
+ return classname;
+ }
+
+ /** This method will find the next parent caller and return their class name, omitting package names.
+ *
+ * @param directCaller used to prevent this method from returning the caller itself. Null if supposed to be ignored.
+ * @return the name of the calling class. */
+ public static final String getCaller(String... directCaller)
+ {
+ if (directCaller == null || directCaller.length == 0)
+ return getCaller();
+ StackTraceElement[] stackTrace = (new Exception()).getStackTrace();
+ String classname = "Utils";
+ List callers = Arrays.asList(directCaller);
+ for (int i = 0; callers.contains(classname) || classname.equals("Utils"); i++)
+ {
+ classname = stackTrace[i].getClassName().replaceAll(".*\\.", "");
+ }
+ return classname;
+ }
+
+ /** Provides a uniform way of getting the date for all modules.
+ *
+ * @return The current date in the format "[dd-mm-yyyy hh:mm:ss]" */
+ public static String getDate()
+ {
+ Date date = new Date(System.currentTimeMillis());
+ return dateFormat.format(date);
+ }
+
+ /** Provides a uniform way of getting the (display)name of a @CommandSender.
+ *
+ * @param sender The @CommandSender to get the name of.
+ * @return The DisplayName of the @CommandSender or if not a @Player, the name in blue. */
+ public static String getName(CommandSender sender)
+ {
+ if (sender instanceof Player)
+ return ((Player) sender).getDisplayName();
+ else
+ return "§9" + sender.getName();
+ }
+
+ /** Provides a uniform way of getting the UUID of a @CommandSender.
+ *
+ * @param sender The @CommandSender to get the UUID of.
+ * @return The UUID of the @CommandSender or if not a player, "CONSOLE" in blue. */
+ public static String getID(CommandSender sender)
+ {
+ String id;
+ if (sender instanceof Player)
+ id = ((Player) sender).getUniqueId().toString();
+ else
+ id = "CONSOLE";
+ return id;
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/Config.java b/src/com/redstoner/misc/mysql/Config.java
new file mode 100644
index 0000000..b51446b
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/Config.java
@@ -0,0 +1,278 @@
+package com.redstoner.misc.mysql;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import com.redstoner.exceptions.NonSaveableConfigException;
+import com.redstoner.faucet.Faucet;
+
+public class Config
+{
+ private File file;
+ private JSONObject config;
+ private JSONParser parser;
+
+ public Config()
+ {
+ file = null;
+ parser = new JSONParser();
+ config = new JSONObject();
+ }
+
+ public Config(JSONObject config)
+ {
+ this.file = null;
+ this.parser = new JSONParser();
+ this.config = config;
+ }
+
+ private Config(File file) throws IOException, ParseException
+ {
+ this.file = file;
+ parser = new JSONParser();
+ if (file.exists())
+ {
+ config = loadConfig(file);
+ }
+ else
+ {
+ config = new JSONObject();
+ }
+ }
+
+ public static final Config getConfig(String fileName) throws IOException, ParseException
+ {
+ return new Config(new File(Faucet.plugin.getDataFolder(), fileName));
+ }
+
+ public static final Config getConfig(File file) throws IOException, ParseException
+ {
+ return new Config(file);
+ }
+
+ private JSONObject loadConfig(File file) throws IOException, ParseException
+ {
+ FileReader reader = new FileReader(file);
+ return (JSONObject) parser.parse(reader);
+ }
+
+ @Override
+ public String toString()
+ {
+ return config.toJSONString();
+ }
+
+ public JSONObject asObject()
+ {
+ return config;
+ }
+
+ public void save() throws IOException, NonSaveableConfigException
+ {
+ if (file == null)
+ {
+ throw new NonSaveableConfigException();
+ }
+ PrintWriter writer = new PrintWriter(file);
+ writer.write(config.toJSONString());
+ writer.close();
+ }
+
+ public void refresh() throws IOException, ParseException, NonSaveableConfigException
+ {
+ if (file == null)
+ {
+ throw new NonSaveableConfigException();
+ }
+ loadConfig(file);
+ }
+
+ public void setFile(String fileName)
+ {
+ file = new File(Faucet.plugin.getDataFolder(), fileName);
+ }
+
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void put(String key, String value)
+ {
+ config.put(key, value);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void put(String key, List value)
+ {
+ JSONArray array = new JSONArray();
+ for (String entry : value)
+ {
+ array.add(entry);
+ }
+ config.put(key, array);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void putArray(String key, JSONArray value)
+ {
+ config.put(key, value);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void put(String key, Map value)
+ {
+ JSONObject object = new JSONObject();
+ for (String valKey : value.keySet())
+ {
+ String valVal = value.get(valKey);
+ object.put(valKey, valVal);
+ }
+ config.put(key, object);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void put(String key, JSONObject value)
+ {
+ config.put(key, value);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void putAll(Map entry)
+ {
+ for (String key : entry.keySet())
+ {
+ String value = entry.get(key);
+ config.put(key, value);
+ }
+ }
+
+ public boolean containsKey(String key)
+ {
+ return config.containsKey(key);
+ }
+
+ public String get(String key)
+ {
+ if (containsKey(key))
+ {
+ Object value = config.get(key);
+ if (value instanceof String)
+ {
+ return (String) value;
+ }
+ }
+ return null;
+ }
+
+ public String getOrDefault(String key, String defaultValue)
+ {
+ if (containsKey(key))
+ {
+ Object value = config.get(key);
+ if (value instanceof String)
+ {
+ return (String) value;
+ }
+ return null;
+ }
+ else
+ {
+ return defaultValue;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public List getList(String key)
+ {
+ if (containsKey(key))
+ {
+ Object value = config.get(key);
+ if (value instanceof JSONArray)
+ {
+ JSONArray array = (JSONArray) value;
+ List output = new ArrayList<>();
+ for (String entry : (String[]) array.toArray(new String[0]))
+ {
+ output.add(entry);
+ }
+ return output;
+ }
+ }
+ return null;
+ }
+
+ public JSONArray getArray(String key)
+ {
+ if (containsKey(key))
+ {
+ Object value = config.get(key);
+ if (value instanceof JSONArray)
+ {
+ JSONArray array = (JSONArray) value;
+ return array;
+ }
+ }
+ return null;
+ }
+
+ public Map getMap(String key)
+ {
+ if (containsKey(key))
+ {
+ Object value = config.get(key);
+ if (value instanceof JSONObject)
+ {
+ JSONObject object = (JSONObject) value;
+ @SuppressWarnings("unchecked")
+ Set> entrySet = object.entrySet();
+ Map output = new HashMap<>();
+ for (Map.Entry entry : entrySet)
+ {
+ output.put(entry.getKey(), entry.getValue());
+ }
+ return output;
+ }
+ }
+ return null;
+ }
+
+ public JSONObject getObject(String key)
+ {
+ if (containsKey(key))
+ {
+ Object value = config.get(key);
+ if (value instanceof JSONObject)
+ {
+ JSONObject object = (JSONObject) value;
+ return object;
+ }
+ }
+ return null;
+ }
+
+ public void remove(String key)
+ {
+ config.remove(key);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Set> getAll()
+ {
+ return config.entrySet();
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/JSONManager.java b/src/com/redstoner/misc/mysql/JSONManager.java
new file mode 100644
index 0000000..68b4592
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/JSONManager.java
@@ -0,0 +1,107 @@
+package com.redstoner.misc.mysql;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import com.redstoner.faucet.Faucet;
+
+public class JSONManager
+{
+ public static Map getConfiguration(String fileName)
+ {
+ File file = new File(Faucet.plugin.getDataFolder(), fileName);
+ if (!file.exists())
+ {
+ try
+ {
+ PrintWriter writer = new PrintWriter(file.getAbsolutePath(), "UTF-8");
+ writer.println("{}");
+ writer.close();
+ }
+ catch (FileNotFoundException | UnsupportedEncodingException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ try
+ {
+ return loadMap(file);
+ }
+ catch (IOException | ParseException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static void saveConfiguration(Map config, String fileName)
+ {
+ try
+ {
+ saveMap(new File(Faucet.plugin.getDataFolder(), fileName), config);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void saveList(File file, List entries) throws IOException
+ {
+ JSONArray array = new JSONArray();
+ array.addAll(entries);
+ FileWriter writer = new FileWriter(file);
+ writer.write(array.toJSONString());
+ writer.close();
+ }
+
+ public static List loadList(File file) throws IOException, ParseException
+ {
+ FileReader read = new FileReader(file);
+ List entries = new ArrayList<>();
+ JSONArray array = (JSONArray) new JSONParser().parse(read);
+ for (Object o : array)
+ {
+ entries.add((Serializable) o);
+ }
+ return entries;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void saveMap(File file, Map entries) throws IOException
+ {
+ JSONObject map = new JSONObject();
+ map.putAll(entries);
+ FileWriter writer = new FileWriter(file);
+ writer.write(map.toJSONString());
+ writer.close();
+ }
+
+ public static Map loadMap(File file) throws IOException, ParseException
+ {
+ FileReader reader = new FileReader(file);
+ JSONObject map = (JSONObject) new JSONParser().parse(reader);
+ Map entries = new HashMap<>();
+ for (Object o : map.keySet())
+ {
+ entries.put((Serializable) o, (Serializable) map.get(o));
+ }
+ return entries;
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/MysqlHandler.java b/src/com/redstoner/misc/mysql/MysqlHandler.java
new file mode 100644
index 0000000..9a34182
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/MysqlHandler.java
@@ -0,0 +1,115 @@
+package com.redstoner.misc.mysql;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.json.simple.parser.ParseException;
+
+import com.redstoner.faucet.Faucet;
+import com.redstoner.misc.mysql.elements.MysqlDatabase;
+
+public class MysqlHandler
+{
+ public static MysqlHandler INSTANCE;
+ private String url, username, password;
+
+ public MysqlHandler(String hostname, int port, String username, String password)
+ {
+ this.url = "jdbc:mysql://" + hostname + ":" + port + "/";
+ this.username = username;
+ this.password = password;
+ }
+
+ public static void init()
+ {
+ Map mysqlCredentials = new HashMap<>();
+ File mysqlCredentialsFile = new File(Faucet.plugin.getDataFolder(), "mysqlCredentials.json");
+ if (mysqlCredentialsFile.exists())
+ {
+ try
+ {
+ mysqlCredentials = JSONManager.loadMap(mysqlCredentialsFile);
+ }
+ catch (IOException | ParseException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ else
+ {
+ Bukkit.getConsoleSender().sendMessage(
+ ChatColor.RED + "MySQL config does not exist, creating an example one, things might (will) break!");
+ mysqlCredentials.put("hostname", "localhost");
+ mysqlCredentials.put("port", "3306");
+ mysqlCredentials.put("username", "your username here");
+ mysqlCredentials.put("password", "your password here");
+ try
+ {
+ JSONManager.saveMap(mysqlCredentialsFile, mysqlCredentials);
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ String hostname = (String) mysqlCredentials.get("hostname");
+ int port = Integer.valueOf((String) mysqlCredentials.get("port"));
+ String username = (String) mysqlCredentials.get("username");
+ String password = (String) mysqlCredentials.get("password");
+ INSTANCE = new MysqlHandler(hostname, port, username, password);
+ }
+
+ private Connection getConnection(String databaseName) throws IllegalStateException
+ {
+ Connection connection = null;
+ try
+ {
+ connection = DriverManager.getConnection(url + databaseName, username, password);
+ }
+ catch (SQLException e)
+ {
+ throw new IllegalStateException("Cannot connect to the database!", e);
+ }
+ return connection;
+ }
+
+ public MysqlDatabase getDatabase(String databaseName)
+ {
+ return new MysqlDatabase(getConnection(databaseName));
+ }
+
+ public List getDatabases()
+ {
+ try
+ {
+ List databases = new ArrayList<>();
+ Connection connection = DriverManager.getConnection(url.substring(0, url.length()), username, password);
+ DatabaseMetaData metadata = connection.getMetaData();
+ ResultSet queryResults = metadata.getCatalogs();
+ while (queryResults.next())
+ {
+ String databaseName = queryResults.getString("TABLE_CAT");
+ databases.add(new MysqlDatabase(getConnection(databaseName)));
+ }
+ connection.close();
+ return databases;
+ }
+ catch (SQLException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/MysqlQueryHandler.java b/src/com/redstoner/misc/mysql/MysqlQueryHandler.java
new file mode 100644
index 0000000..f89a08a
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/MysqlQueryHandler.java
@@ -0,0 +1,33 @@
+package com.redstoner.misc.mysql;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class MysqlQueryHandler {
+ public static ResultSet queryResult(Connection connection, String query) {
+ try {
+ Statement statement = connection.createStatement();
+ ResultSet results = statement.executeQuery(query);
+
+ return results;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static boolean queryNoResult(Connection connection, String query) {
+ try {
+ CallableStatement statement = connection.prepareCall(query);
+ statement.execute();
+
+ return true;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/elements/ConstraintOperator.java b/src/com/redstoner/misc/mysql/elements/ConstraintOperator.java
new file mode 100644
index 0000000..45cb33c
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/elements/ConstraintOperator.java
@@ -0,0 +1,24 @@
+package com.redstoner.misc.mysql.elements;
+
+public enum ConstraintOperator {
+ LESS_THAN, GREATER_THAN, EQUAL, NOT_EQUAL, LESS_THAN_OR_EQUAL, GREATER_THAN_OR_EQUAL;
+
+ public String toString() {
+ switch (this) {
+ case LESS_THAN:
+ return "<";
+ case GREATER_THAN:
+ return ">";
+ case EQUAL:
+ return "=";
+ case NOT_EQUAL:
+ return "!=";
+ case LESS_THAN_OR_EQUAL:
+ return "<=";
+ case GREATER_THAN_OR_EQUAL:
+ return ">=";
+ default:
+ return "=";
+ }
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/elements/MysqlConstraint.java b/src/com/redstoner/misc/mysql/elements/MysqlConstraint.java
new file mode 100644
index 0000000..d651344
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/elements/MysqlConstraint.java
@@ -0,0 +1,24 @@
+package com.redstoner.misc.mysql.elements;
+
+public class MysqlConstraint {
+ private String fieldName, value;
+ private ConstraintOperator operator;
+
+ public MysqlConstraint(String fieldName, ConstraintOperator operator, String value) {
+ this.fieldName = fieldName;
+ this.operator = operator;
+ this.value = value;
+ }
+
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public ConstraintOperator getOperator() {
+ return operator;
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/elements/MysqlDatabase.java b/src/com/redstoner/misc/mysql/elements/MysqlDatabase.java
new file mode 100644
index 0000000..91c0fe4
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/elements/MysqlDatabase.java
@@ -0,0 +1,90 @@
+package com.redstoner.misc.mysql.elements;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.redstoner.misc.mysql.MysqlQueryHandler;
+
+public class MysqlDatabase {
+ private Connection connection;
+
+ public MysqlDatabase(Connection connection) {
+ this.connection = connection;
+ }
+
+ public String getName() {
+ try {
+ return connection.getCatalog();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public MysqlTable getTable(String name) {
+ return new MysqlTable(this, name);
+ }
+
+ public boolean createTable(String name, MysqlField... description) {
+ return MysqlQueryHandler.queryNoResult(connection, "CREATE TABLE `" + name + "` " + getDescription(description) + ";");
+ }
+
+ public boolean createTableIfNotExists(String name, MysqlField... description) {
+ return MysqlQueryHandler.queryNoResult(connection, "CREATE TABLE IF NOT EXISTS `" + name + "` " + getDescription(description) + ";");
+ }
+
+ public boolean dropTable(String name) {
+ return MysqlQueryHandler.queryNoResult(connection, "DROP TABLE `" + name + "`;");
+ }
+
+ public boolean drop() {
+ return MysqlQueryHandler.queryNoResult(connection, "DROP DATABASE `" + getName() + "`;");
+ }
+
+ public List getTables() {
+ try {
+ List tables = new ArrayList<>();
+ DatabaseMetaData metadata = connection.getMetaData();
+ ResultSet queryResults = metadata.getTables(null, null, "%", null);
+
+ while (queryResults.next()) {
+ tables.add(new MysqlTable(this, queryResults.getString(3)));
+ }
+
+ return tables;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ protected Connection getConnection() {
+ return connection;
+ }
+
+ private String getDescription(MysqlField... description) {
+ String desc = "(";
+
+ for (int i = 0; i < description.length; i++) {
+ String nil = "";
+
+ if (description[i].canBeNull()) {
+ nil = " NOT NULL";
+ }
+
+ desc += "`" + description[i].getName() + "` " + description[i].getType().getName() + nil;
+
+ if (i < description.length - 1) {
+ desc += ",";
+ }
+ }
+
+ desc += ")";
+
+ return desc;
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/elements/MysqlField.java b/src/com/redstoner/misc/mysql/elements/MysqlField.java
new file mode 100644
index 0000000..61cba2e
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/elements/MysqlField.java
@@ -0,0 +1,33 @@
+package com.redstoner.misc.mysql.elements;
+
+import com.redstoner.misc.mysql.types.MysqlType;
+
+public class MysqlField {
+ private String name;
+ private MysqlType type;
+ private boolean canBeNull;
+
+ public MysqlField(String name, MysqlType type, boolean canBeNull) {
+ this.name = name;
+ this.type = type;
+ this.canBeNull = canBeNull;
+ }
+
+ public MysqlField(String name, String type, boolean canBeNull) {
+ this.name = name;
+ this.type = MysqlType.getTypeFromString(type);
+ this.canBeNull = canBeNull;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public MysqlType getType() {
+ return type;
+ }
+
+ public boolean canBeNull() {
+ return canBeNull;
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/elements/MysqlResult.java b/src/com/redstoner/misc/mysql/elements/MysqlResult.java
new file mode 100644
index 0000000..6db0769
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/elements/MysqlResult.java
@@ -0,0 +1,16 @@
+package com.redstoner.misc.mysql.elements;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public class MysqlResult {
+ private ResultSet results;
+
+ public MysqlResult(ResultSet results) {
+ this.results = results;
+ }
+
+ public Object getObject(int columnIndex, Class> type) throws SQLException {
+ return results.getObject(columnIndex, type);
+ }
+}
diff --git a/src/com/redstoner/misc/mysql/elements/MysqlTable.java b/src/com/redstoner/misc/mysql/elements/MysqlTable.java
new file mode 100644
index 0000000..6656fcd
--- /dev/null
+++ b/src/com/redstoner/misc/mysql/elements/MysqlTable.java
@@ -0,0 +1,133 @@
+package com.redstoner.misc.mysql.elements;
+
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.redstoner.misc.mysql.MysqlQueryHandler;
+
+public class MysqlTable
+{
+ private MysqlDatabase database;
+ private String name;
+
+ public MysqlTable(MysqlDatabase database, String name)
+ {
+ this.database = database;
+ this.name = name;
+ }
+
+ public String getName()
+ {
+ return this.name;
+ }
+
+ public MysqlField[] describe()
+ {
+ try
+ {
+ List description = new ArrayList<>();
+ DatabaseMetaData metadata = database.getConnection().getMetaData();
+ ResultSet queryResults = metadata.getColumns(null, null, name, null);
+ while (queryResults.next())
+ {
+ description.add(new MysqlField(queryResults.getString(4),
+ queryResults.getString(6).split(" ")[0] + "(" + queryResults.getString(7) + ")",
+ queryResults.getBoolean(11)));
+ }
+ return description.toArray(new MysqlField[0]);
+ }
+ catch (SQLException e)
+ {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public boolean insert(String... values)
+ {
+ MysqlField[] description = describe();
+ if (values.length > 0 && values.length == description.length)
+ {
+ String val = "(\"" + String.join("\",\"", values) + "\")";
+ return MysqlQueryHandler.queryNoResult(database.getConnection(),
+ "INSERT INTO `" + name + "` VALUES " + val + ";");
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public Object[] get(String fieldName, MysqlConstraint... constraints)
+ {
+ ResultSet results = MysqlQueryHandler.queryResult(database.getConnection(),
+ "SELECT " + fieldName + " FROM `" + name + "`" + getConstraints(constraints) + ";");
+ List