summaryrefslogtreecommitdiff
path: root/src/main/java/com
diff options
context:
space:
mode:
authorDavid <david@panic.tk>2018-11-07 23:50:06 +0100
committerDavid <david@panic.tk>2018-11-07 23:50:06 +0100
commit604cf01967ede98bf5024e4926bb0777fc4e8eee (patch)
treee2fa63d7e683769ee3bf3eddc75280648e92eb04 /src/main/java/com
parente86c52ef7c0e1e33c6af0e8674b038976bec11cc (diff)
Converted Modules to gradle
Diffstat (limited to 'src/main/java/com')
-rw-r--r--src/main/java/com/earth2me/essentials/utils/DateUtil.java186
-rw-r--r--src/main/java/com/redstoner/modules/abot/Abot.cmd7
-rw-r--r--src/main/java/com/redstoner/modules/abot/Abot.java68
-rw-r--r--src/main/java/com/redstoner/modules/adminchat/Adminchat.cmd42
-rw-r--r--src/main/java/com/redstoner/modules/adminchat/Adminchat.java214
-rw-r--r--src/main/java/com/redstoner/modules/afk/AFK.cmd24
-rw-r--r--src/main/java/com/redstoner/modules/afk/AFK.java235
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/BlockPlaceMods.java206
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/Mod.java24
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModAbstract.java94
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModInventory.java195
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledAbstract.java80
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledCauldron.java49
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledLogPlaceAbstract.java40
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledObserver.java43
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledPiston.java46
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledStep.java40
-rw-r--r--src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledTorch.java91
-rw-r--r--src/main/java/com/redstoner/modules/buildchat/BuildChat.cmd42
-rw-r--r--src/main/java/com/redstoner/modules/buildchat/BuildChat.java207
-rw-r--r--src/main/java/com/redstoner/modules/buildteam/BuildTeam.cmd22
-rw-r--r--src/main/java/com/redstoner/modules/buildteam/BuildTeam.java56
-rw-r--r--src/main/java/com/redstoner/modules/chat/Chat.cmd81
-rw-r--r--src/main/java/com/redstoner/modules/chat/Chat.java215
-rw-r--r--src/main/java/com/redstoner/modules/chatalias/Chatalias.cmd16
-rw-r--r--src/main/java/com/redstoner/modules/chatalias/Chatalias.java317
-rw-r--r--src/main/java/com/redstoner/modules/chatgroups/Chatgroups.cmd35
-rw-r--r--src/main/java/com/redstoner/modules/chatgroups/Chatgroups.java400
-rw-r--r--src/main/java/com/redstoner/modules/check/Check.cmd8
-rw-r--r--src/main/java/com/redstoner/modules/check/Check.java247
-rw-r--r--src/main/java/com/redstoner/modules/clear/Clear.cmd13
-rw-r--r--src/main/java/com/redstoner/modules/clear/Clear.java44
-rw-r--r--src/main/java/com/redstoner/modules/cycle/Cycle.cmd12
-rw-r--r--src/main/java/com/redstoner/modules/cycle/Cycle.java142
-rw-r--r--src/main/java/com/redstoner/modules/damnspam/DamnSpam.cmd15
-rw-r--r--src/main/java/com/redstoner/modules/damnspam/DamnSpam.java350
-rw-r--r--src/main/java/com/redstoner/modules/damnspam/SpamInput.java17
-rw-r--r--src/main/java/com/redstoner/modules/datamanager/DataManager.cmd34
-rw-r--r--src/main/java/com/redstoner/modules/datamanager/DataManager.java1029
-rw-r--r--src/main/java/com/redstoner/modules/discord/Discord.cmd8
-rw-r--r--src/main/java/com/redstoner/modules/discord/Discord.java118
-rw-r--r--src/main/java/com/redstoner/modules/friends/Friends.cmd38
-rw-r--r--src/main/java/com/redstoner/modules/friends/Friends.java360
-rw-r--r--src/main/java/com/redstoner/modules/ignore/Ignore.cmd22
-rw-r--r--src/main/java/com/redstoner/modules/ignore/Ignore.java159
-rw-r--r--src/main/java/com/redstoner/modules/lagchunks/LagChunks.cmd19
-rw-r--r--src/main/java/com/redstoner/modules/lagchunks/LagChunks.java82
-rw-r--r--src/main/java/com/redstoner/modules/lagchunks/LaggyChunk.java21
-rw-r--r--src/main/java/com/redstoner/modules/list/List.cmd38
-rw-r--r--src/main/java/com/redstoner/modules/list/List.java194
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/CancelledEventsHandler.java95
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/CryptographyHandler.java53
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.cmd49
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.java263
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/RepeatingLoginRunnable.java37
-rw-r--r--src/main/java/com/redstoner/modules/logs/LogEntry.java71
-rw-r--r--src/main/java/com/redstoner/modules/logs/LogHandler.java200
-rw-r--r--src/main/java/com/redstoner/modules/logs/Logs.cmd34
-rw-r--r--src/main/java/com/redstoner/modules/logs/Logs.java157
-rw-r--r--src/main/java/com/redstoner/modules/mentio/Mentio.cmd16
-rw-r--r--src/main/java/com/redstoner/modules/mentio/Mentio.java180
-rw-r--r--src/main/java/com/redstoner/modules/message/Message.cmd43
-rw-r--r--src/main/java/com/redstoner/modules/message/Message.java226
-rw-r--r--src/main/java/com/redstoner/modules/misc/Misc.cmd66
-rw-r--r--src/main/java/com/redstoner/modules/misc/Misc.java336
-rw-r--r--src/main/java/com/redstoner/modules/motd/Motd.cmd14
-rw-r--r--src/main/java/com/redstoner/modules/motd/Motd.java59
-rw-r--r--src/main/java/com/redstoner/modules/nametags/Nametags.cmd11
-rw-r--r--src/main/java/com/redstoner/modules/nametags/Nametags.java130
-rw-r--r--src/main/java/com/redstoner/modules/naming/Naming.cmd24
-rw-r--r--src/main/java/com/redstoner/modules/naming/Naming.java75
-rw-r--r--src/main/java/com/redstoner/modules/onlineplayers/OnlinePlayers.java92
-rw-r--r--src/main/java/com/redstoner/modules/reports/Reports.cmd24
-rw-r--r--src/main/java/com/redstoner/modules/reports/Reports.java154
-rw-r--r--src/main/java/com/redstoner/modules/saylol/Saylol.cmd47
-rw-r--r--src/main/java/com/redstoner/modules/saylol/Saylol.java300
-rw-r--r--src/main/java/com/redstoner/modules/scriptutils/Scriptutils.cmd119
-rw-r--r--src/main/java/com/redstoner/modules/scriptutils/Scriptutils.java177
-rw-r--r--src/main/java/com/redstoner/modules/seen/Seen.cmd53
-rw-r--r--src/main/java/com/redstoner/modules/seen/Seen.java320
-rw-r--r--src/main/java/com/redstoner/modules/signalstrength/SignalStrength.cmd14
-rw-r--r--src/main/java/com/redstoner/modules/signalstrength/SignalStrength.java194
-rw-r--r--src/main/java/com/redstoner/modules/skullclick/SkullClick.java56
-rw-r--r--src/main/java/com/redstoner/modules/socialspy/Socialspy.cmd72
-rw-r--r--src/main/java/com/redstoner/modules/socialspy/Socialspy.java377
-rw-r--r--src/main/java/com/redstoner/modules/tag/Tag.cmd22
-rw-r--r--src/main/java/com/redstoner/modules/tag/Tag.java147
-rw-r--r--src/main/java/com/redstoner/modules/teleport/Teleport.cmd142
-rw-r--r--src/main/java/com/redstoner/modules/teleport/Teleport.java185
-rw-r--r--src/main/java/com/redstoner/modules/tilechunks/LaggyTileChunk.java21
-rw-r--r--src/main/java/com/redstoner/modules/tilechunks/TileChunks.cmd19
-rw-r--r--src/main/java/com/redstoner/modules/tilechunks/TileChunks.java83
-rw-r--r--src/main/java/com/redstoner/modules/vanish/Vanish.cmd33
-rw-r--r--src/main/java/com/redstoner/modules/vanish/Vanish.java260
-rw-r--r--src/main/java/com/redstoner/modules/warn/Warn.cmd15
-rw-r--r--src/main/java/com/redstoner/modules/warn/Warn.java29
-rw-r--r--src/main/java/com/redstoner/modules/webtoken/WebToken.cmd21
-rw-r--r--src/main/java/com/redstoner/modules/webtoken/WebToken.java225
-rw-r--r--src/main/java/com/redstoner/utils/CommandException.java29
-rw-r--r--src/main/java/com/redstoner/utils/CommandMap.java23
-rw-r--r--src/main/java/com/redstoner/utils/ItemProperties.java272
-rw-r--r--src/main/java/com/redstoner/utils/ThrowingSupplier.java12
102 files changed, 11721 insertions, 0 deletions
diff --git a/src/main/java/com/earth2me/essentials/utils/DateUtil.java b/src/main/java/com/earth2me/essentials/utils/DateUtil.java
new file mode 100644
index 0000000..80daa36
--- /dev/null
+++ b/src/main/java/com/earth2me/essentials/utils/DateUtil.java
@@ -0,0 +1,186 @@
+package com.earth2me.essentials.utils;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.redstoner.annotations.Version;
+
+/** Original source is at https://github.com/essentials/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/utils/DateUtil.java
+ * This code has been modified slightly to fit the custom needs of redstoner.
+ *
+ * @author khobbits, FearFree */
+@Version(major = 4, minor = 0, revision = 0, compatible = 4)
+public class DateUtil
+{
+ private static Pattern timePattern = Pattern.compile("(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?"
+ + "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?"
+ + "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*(?:s[a-z]*)?)?",
+ Pattern.CASE_INSENSITIVE);
+
+ public static String removeTimePattern(String input)
+ {
+ return timePattern.matcher(input).replaceFirst("").trim();
+ }
+
+ public static long parseDateDiff(String time, boolean future) throws Exception
+ {
+ Matcher m = timePattern.matcher(time);
+ int years = 0;
+ int months = 0;
+ int weeks = 0;
+ int days = 0;
+ int hours = 0;
+ int minutes = 0;
+ int seconds = 0;
+ boolean found = false;
+ while (m.find())
+ {
+ if (m.group() == null || m.group().isEmpty())
+ {
+ continue;
+ }
+ for (int i = 0; i < m.groupCount(); i++)
+ {
+ if (m.group(i) != null && !m.group(i).isEmpty())
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ {
+ if (m.group(1) != null && !m.group(1).isEmpty())
+ {
+ years = Integer.parseInt(m.group(1));
+ }
+ if (m.group(2) != null && !m.group(2).isEmpty())
+ {
+ months = Integer.parseInt(m.group(2));
+ }
+ if (m.group(3) != null && !m.group(3).isEmpty())
+ {
+ weeks = Integer.parseInt(m.group(3));
+ }
+ if (m.group(4) != null && !m.group(4).isEmpty())
+ {
+ days = Integer.parseInt(m.group(4));
+ }
+ if (m.group(5) != null && !m.group(5).isEmpty())
+ {
+ hours = Integer.parseInt(m.group(5));
+ }
+ if (m.group(6) != null && !m.group(6).isEmpty())
+ {
+ minutes = Integer.parseInt(m.group(6));
+ }
+ if (m.group(7) != null && !m.group(7).isEmpty())
+ {
+ seconds = Integer.parseInt(m.group(7));
+ }
+ break;
+ }
+ }
+ if (!found)
+ {
+ throw new Exception(("illegalDate"));
+ }
+ Calendar c = new GregorianCalendar();
+ if (years > 0)
+ {
+ c.add(Calendar.YEAR, years * (future ? 1 : -1));
+ }
+ if (months > 0)
+ {
+ c.add(Calendar.MONTH, months * (future ? 1 : -1));
+ }
+ if (weeks > 0)
+ {
+ c.add(Calendar.WEEK_OF_YEAR, weeks * (future ? 1 : -1));
+ }
+ if (days > 0)
+ {
+ c.add(Calendar.DAY_OF_MONTH, days * (future ? 1 : -1));
+ }
+ if (hours > 0)
+ {
+ c.add(Calendar.HOUR_OF_DAY, hours * (future ? 1 : -1));
+ }
+ if (minutes > 0)
+ {
+ c.add(Calendar.MINUTE, minutes * (future ? 1 : -1));
+ }
+ if (seconds > 0)
+ {
+ c.add(Calendar.SECOND, seconds * (future ? 1 : -1));
+ }
+ Calendar max = new GregorianCalendar();
+ max.add(Calendar.YEAR, 10);
+ if (c.after(max))
+ {
+ return max.getTimeInMillis();
+ }
+ return c.getTimeInMillis();
+ }
+
+ static int dateDiff(int type, Calendar fromDate, Calendar toDate, boolean future)
+ {
+ int diff = 0;
+ long savedDate = fromDate.getTimeInMillis();
+ while ((future && !fromDate.after(toDate)) || (!future && !fromDate.before(toDate)))
+ {
+ savedDate = fromDate.getTimeInMillis();
+ fromDate.add(type, future ? 1 : -1);
+ diff++;
+ }
+ diff--;
+ fromDate.setTimeInMillis(savedDate);
+ return diff;
+ }
+
+ public static String formatDateDiff(long date)
+ {
+ Calendar c = new GregorianCalendar();
+ c.setTimeInMillis(date);
+ Calendar now = new GregorianCalendar();
+ return DateUtil.formatDateDiff(now, c);
+ }
+
+ public static String formatDateDiff(Calendar fromDate, Calendar toDate)
+ {
+ boolean future = false;
+ if (toDate.equals(fromDate))
+ {
+ return ("now");
+ }
+ if (toDate.after(fromDate))
+ {
+ future = true;
+ }
+ StringBuilder sb = new StringBuilder();
+ int[] types = new int[] {Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, Calendar.HOUR_OF_DAY,
+ Calendar.MINUTE, Calendar.SECOND};
+ String[] names = new String[] {"year", "years", "month", "months", "day", "days", "hour", "hours", "minute",
+ "minutes", "second", "seconds"};
+ int accuracy = 0;
+ for (int i = 0; i < types.length; i++)
+ {
+ if (accuracy > 2)
+ {
+ break;
+ }
+ int diff = dateDiff(types[i], fromDate, toDate, future);
+ if (diff > 0)
+ {
+ accuracy++;
+ sb.append(" ").append(diff).append(" ").append(names[i * 2 + (diff > 1 ? 1 : 0)]);
+ }
+ }
+ if (sb.length() == 0)
+ {
+ return "now";
+ }
+ return sb.toString().trim();
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/abot/Abot.cmd b/src/main/java/com/redstoner/modules/abot/Abot.cmd
new file mode 100644
index 0000000..c8bb2d8
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/abot/Abot.cmd
@@ -0,0 +1,7 @@
+command abot {
+ reload {
+ help Reloads answers from the .json file.;
+ run abot_reload;
+ perm utils.abot.reload;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/abot/Abot.java b/src/main/java/com/redstoner/modules/abot/Abot.java
new file mode 100644
index 0000000..728d61c
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/abot/Abot.java
@@ -0,0 +1,68 @@
+package com.redstoner.modules.abot;
+
+import java.io.File;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Abot implements Module, Listener
+{
+ private File answerFile = new File(Main.plugin.getDataFolder(), "abot.json");
+ JSONArray answers;
+
+ @EventHandler
+ public void onPlayerChat(AsyncPlayerChatEvent event)
+ {
+ for (Object rawObject : answers)
+ {
+ JSONObject entry = (JSONObject) rawObject;
+ JSONArray regexes = (JSONArray) entry.get("regex");
+ for (Object regex : regexes)
+ {
+ if (event.getMessage().toLowerCase().matches((String) regex))
+ {
+ Object hideperm = entry.get("hide-perm");
+ if (hideperm == null || !event.getPlayer().hasPermission((String) hideperm))
+ {
+ event.setCancelled(true);
+ getLogger().message(event.getPlayer(), (String) entry.get("message"));
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ @Command(hook = "abot_reload")
+ public void loadAnswers(CommandSender sender)
+ {
+ answers = JsonManager.getArray(answerFile);
+ if (answers == null)
+ answers = new JSONArray();
+ getLogger().message(sender, "Loaded the abot.json file!");
+ }
+
+ @Override
+ public boolean onEnable()
+ {
+ loadAnswers(Bukkit.getConsoleSender());
+ return true;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/adminchat/Adminchat.cmd b/src/main/java/com/redstoner/modules/adminchat/Adminchat.cmd
new file mode 100644
index 0000000..b083eb9
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/adminchat/Adminchat.cmd
@@ -0,0 +1,42 @@
+command ac {
+ [string:message...] {
+ help Sends a message in Admin Chat;
+ perm utils.ac;
+ run ac_msg message;
+ }
+}
+command acn {
+ [string:name] [string:message...] {
+ help Sends a message in Admin Chat;
+ perm utils.ac;
+ type console;
+ run acn_msg name message;
+ }
+}
+
+command ackey {
+ [string:key] {
+ help Sets your Admin Chat key;
+ perm utils.ac;
+ type player;
+ run setackey key;
+ }
+}
+
+command act {
+ on {
+ help Turns on act;
+ perm utils.ac;
+ run act_on;
+ }
+ off {
+ help Turns off act;
+ perm utils.ac;
+ run act_off;
+ }
+ [empty] {
+ help toggles Admin Chat;
+ perm utils.ac;
+ run act;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/adminchat/Adminchat.java b/src/main/java/com/redstoner/modules/adminchat/Adminchat.java
new file mode 100644
index 0000000..d736f8f
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/adminchat/Adminchat.java
@@ -0,0 +1,214 @@
+package com.redstoner.modules.adminchat;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.BroadcastFilter;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+
+import net.nemez.chatapi.ChatAPI;
+
+/** AdminChat module. Allows staff to chat to other staff using /ac \<message\> as well as a one char prefix or a toggle.
+ *
+ * @author Pepich */
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Adminchat implements Module, Listener
+{
+ private static final char defaultKey = ',';
+ private static final File keysLocation = new File(Main.plugin.getDataFolder(), "adminchat_keys.json");
+ private ArrayList<UUID> actoggled;
+ private static JSONObject keys;
+
+ @Override
+ public boolean onEnable()
+ {
+ keys = JsonManager.getObject(keysLocation);
+ if (keys == null)
+ {
+ keys = new JSONObject();
+ saveKeys();
+ }
+ actoggled = new ArrayList<>();
+ return true;
+ }
+
+ @Command(hook = "ac_msg")
+ public boolean acSay(CommandSender sender, String message)
+ {
+ String name;
+ if (sender instanceof Player)
+ name = ((Player) sender).getDisplayName();
+ else
+ name = sender.getName();
+ Utils.broadcast("§8[§cAC§8] §9" + name + "§8: §b", ChatAPI.colorify(sender, message), new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return recipient.hasPermission("utils.ac");
+ }
+ });
+ return true;
+ }
+
+ @Command(hook = "acn_msg")
+ public boolean acnSay(CommandSender sender, String name, String message)
+ {
+ Utils.broadcast("§8[§cAC§8] §9" + name + "§8: §b", ChatAPI.colorify(sender, message), new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return recipient.hasPermission("utils.ac");
+ }
+ });
+ return true;
+ }
+
+ /** Let's a Player toggle their ac-toglge status to allow for automatically sending chat messages to adminchat.
+ *
+ * @param sender the issuer of the command.
+ * @param _void ignored.
+ * @return true. */
+ @Command(hook = "act")
+ public boolean acToggleCommand(CommandSender sender)
+ {
+ if (actoggled.contains(((Player) sender).getUniqueId()))
+ {
+ actoggled.remove(((Player) sender).getUniqueId());
+ getLogger().message(sender, "ACT now §cdisabled");
+ }
+ else
+ {
+ actoggled.add(((Player) sender).getUniqueId());
+ getLogger().message(sender, "ACT now §aenabled");
+ }
+ return true;
+ }
+
+ /** Let's a Player toggle their ac-toglge status to allow for automatically sending chat messages to adminchat.
+ *
+ * @param sender the issuer of the command.
+ * @return true. */
+ @Command(hook = "act_on")
+ public boolean acToggleOnCommand(CommandSender sender)
+ {
+ if (!actoggled.contains(((Player) sender).getUniqueId()))
+ {
+ actoggled.add(((Player) sender).getUniqueId());
+ getLogger().message(sender, "ACT now §aenabled");
+ }
+ else
+ getLogger().message(sender, "ACT was already enabled");
+ return true;
+ }
+
+ /** Let's a Player toggle their ac-toglge status to allow for automatically sending chat messages to adminchat.
+ *
+ * @param sender the issuer of the command.
+ * @return true. */
+ @Command(hook = "act_off")
+ public boolean acToggleOffCommand(CommandSender sender)
+ {
+ if (actoggled.contains(((Player) sender).getUniqueId()))
+ {
+ actoggled.remove(((Player) sender).getUniqueId());
+ getLogger().message(sender, "ACT now §cdisabled");
+ }
+ else
+ {
+ getLogger().message(sender, "ACT was already disabled");
+ }
+ return true;
+ }
+
+ /** Deals with chat events to allow for ackeys and actoggle.
+ *
+ * @param event the chat event containing the player and the message. */
+ @EventHandler
+ public void onPlayerChat(AsyncPlayerChatEvent event)
+ {
+ Player player = event.getPlayer();
+ if (!player.hasPermission("utils.ac"))
+ return;
+ if (event.getMessage().startsWith(getKey(player)))
+ {
+ event.setCancelled(true);
+ acSay(event.getPlayer(), event.getMessage().replaceFirst(Pattern.quote(getKey(player)), ""));
+ }
+ else if (actoggled.contains(event.getPlayer().getUniqueId()))
+ {
+ event.setCancelled(true);
+ acSay(event.getPlayer(), event.getMessage());
+ }
+ }
+
+ /** Sets the ackey of a Player.
+ *
+ * @param sender the issuer of the command.
+ * @param key the key to be set. Set to NULL or "" to get your current key.
+ * @return true. */
+ @SuppressWarnings("unchecked")
+ @Command(hook = "setackey")
+ public boolean setAcKey(CommandSender sender, String key)
+ {
+ if (key.length() > 1)
+ {
+ getLogger().message(sender, true,
+ "Could not set your key to §6" + key + " §7, it can be at most one char.");
+ return true;
+ }
+ if (key == null || key.length() == 0)
+ {
+ getAcKey(sender);
+ return true;
+ }
+ getLogger().message(sender, "Set your key to §6" + key);
+ keys.put(((Player) sender).getUniqueId().toString(), key + "");
+ saveKeys();
+ return true;
+ }
+
+ /** This method will find the AdminChat key of any player.
+ *
+ * @param player the player to get the key from.
+ * @return the key. */
+ public static String getKey(Player player)
+ {
+ String key = (String) keys.get(player.getUniqueId().toString());
+ return (key == null ? "" + defaultKey : key);
+ }
+
+ /** Prints a Players ackey to their chat.
+ *
+ * @param sender the issuer of the command. */
+ public void getAcKey(CommandSender sender)
+ {
+ getLogger().message(sender, "Your current ackey is §6" + getKey((Player) sender));
+ }
+
+ /** Saves the keys. */
+ private void saveKeys()
+ {
+ JsonManager.save(keys, keysLocation);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/afk/AFK.cmd b/src/main/java/com/redstoner/modules/afk/AFK.cmd
new file mode 100644
index 0000000..6f9385d
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/afk/AFK.cmd
@@ -0,0 +1,24 @@
+command afk {
+ alias eafk;
+ alias away;
+ alias eaway;
+ [empty] {
+ run afk;
+ perm utils.afk;
+ }
+ [optional:-s] {
+ run afks -s;
+ perm utils.afk;
+ }
+ [optional:-s] [string:reason...] {
+ run afk2 -s reason;
+ perm utils.afk;
+ }
+}
+
+command update_afk_listeners {
+ [empty] {
+ run update_afk_listeners;
+ perm utils.afk.admin;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/afk/AFK.java b/src/main/java/com/redstoner/modules/afk/AFK.java
new file mode 100644
index 0000000..810c0bb
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/afk/AFK.java
@@ -0,0 +1,235 @@
+package com.redstoner.modules.afk;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Event;
+import org.bukkit.event.EventException;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.event.player.PlayerEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.plugin.EventExecutor;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.BroadcastFilter;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 0, revision = 6, compatible = 5)
+public class AFK implements Module, Listener
+{
+ private CustomListener listener;
+ boolean move = true, look = false;
+
+ @Override
+ public void firstLoad()
+ {
+ Module.super.firstLoad();
+ DataManager.setConfig("indicator", "&7[AFK]");
+ String[] choices = new String[] {"listen", "ignore"};
+ DataManager.setConfig("move", "listen", choices);
+ DataManager.setConfig("look", "ignore", choices);
+ DataManager.setConfig("chat", "listen", choices);
+ DataManager.setConfig("interact", "listen", choices);
+ DataManager.setConfig("command", "ignore", choices);
+ }
+
+ @Override
+ public void migrate(Version old)
+ {
+ Module.super.migrate(old);
+ if ((old.major() == 4) && (old.minor() == 0) && (old.revision() == 3))
+ {
+ String[] choices = new String[] {"listen", "ignore"};
+ DataManager.setConfig("look", "ignore", choices);
+ }
+ }
+
+ @Override
+ public void postEnable()
+ {
+ Module.super.postEnable();
+ listener = new CustomListener();
+ update_afk_listeners(Bukkit.getConsoleSender());
+ }
+
+ @Override
+ public void onDisable()
+ {
+ Module.super.onDisable();
+ HandlerList.unregisterAll(listener);
+ }
+
+ @Command(hook = "afk")
+ public boolean afk(CommandSender sender)
+ {
+ return afk(sender, false, "");
+ }
+
+ @Command(hook = "afks")
+ public boolean afk(CommandSender sender, boolean silent)
+ {
+ return afk(sender, silent, "");
+ }
+
+ @Command(hook = "afk2")
+ public boolean afk(CommandSender sender, boolean silent, String reason)
+ {
+ if (isafk(sender))
+ {
+ unafk(sender, silent);
+ }
+ else
+ {
+ DataManager.setData(sender, "afk_time", System.currentTimeMillis());
+ DataManager.setData(sender, "afk_reason", reason);
+ DataManager.setState(sender, "afk_silent", silent);
+ DataManager.setState(sender, "afk", true);
+ if (!silent)
+ Utils.broadcast("§7 * ", Utils.getName(sender) + "§7 is now AFK", null);
+ }
+ return true;
+ }
+
+ public void unafk(CommandSender sender, boolean silent)
+ {
+ DataManager.setState(sender, "afk", false);
+ if (!silent)
+ Utils.broadcast("§7 * ", Utils.getName(sender) + "§7 is no longer AFK", null);
+ }
+
+ public boolean isafk(CommandSender sender)
+ {
+ return DataManager.getState(sender, "afk");
+ }
+
+ public boolean isVanished(Player player)
+ {
+ return DataManager.getState(player, "vanished");
+ }
+
+ @Command(hook = "update_afk_listeners")
+ public boolean update_afk_listeners(CommandSender sender)
+ {
+ Utils.broadcast(null, "Updating afk listeners...", new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return recipient.hasPermission("utils.afk.admin");
+ }
+ });
+ move = DataManager.getConfigOrDefault("move", "listen").equals("listen");
+ look = DataManager.getConfigOrDefault("look", "ignore").equals("listen");
+ if (move || look)
+ Bukkit.getPluginManager().registerEvent(PlayerMoveEvent.class, listener, EventPriority.MONITOR, listener,
+ Main.plugin);
+ else
+ PlayerMoveEvent.getHandlerList().unregister(listener);
+ if (DataManager.getConfigOrDefault("chat", "listen").equals("listen"))
+ Bukkit.getPluginManager().registerEvent(PlayerInteractEvent.class, listener, EventPriority.MONITOR,
+ listener, Main.plugin);
+ else
+ PlayerInteractEvent.getHandlerList().unregister(listener);
+ if (DataManager.getConfigOrDefault("interact", "listen").equals("listen"))
+ Bukkit.getPluginManager().registerEvent(AsyncPlayerChatEvent.class, listener, EventPriority.MONITOR,
+ listener, Main.plugin);
+ else
+ AsyncPlayerChatEvent.getHandlerList().unregister(listener);
+ if (DataManager.getConfigOrDefault("command", "ignore").equals("listen"))
+ Bukkit.getPluginManager().registerEvent(PlayerCommandPreprocessEvent.class, listener, EventPriority.MONITOR,
+ listener, Main.plugin);
+ else
+ PlayerCommandPreprocessEvent.getHandlerList().unregister(listener);
+ return true;
+ }
+
+ @EventHandler
+ public void onLeave(PlayerQuitEvent event)
+ {
+ DataManager.setState(event.getPlayer(), "afk", false);
+ }
+}
+
+class CustomListener implements Listener, EventExecutor
+{
+ private boolean move = true, look = false;
+
+ @Override
+ public void execute(Listener listener, Event event) throws EventException
+ {
+ if (event instanceof PlayerEvent)
+ {
+ if (event instanceof PlayerMoveEvent)
+ {
+ PlayerMoveEvent pevent = (PlayerMoveEvent) event;
+ double distance = pevent.getFrom().distance(pevent.getTo());
+ boolean moved = distance > 0;
+ boolean looked = (pevent.getFrom().getPitch() != pevent.getTo().getPitch())
+ || (pevent.getFrom().getYaw() != pevent.getTo().getYaw());
+ if ((move && moved) || (look && looked))
+ {
+ Player player = pevent.getPlayer();
+ if (isafk(player))
+ if (!isVanished(player))
+ unafk(player);
+ }
+ }
+ else
+ {
+ PlayerEvent pevent = (PlayerEvent) event;
+ Player player = pevent.getPlayer();
+ if (isafk(player))
+ if (!isVanished(player))
+ unafk(player);
+ }
+ }
+ }
+
+ public void unafk(CommandSender sender)
+ {
+ DataManager.setState(sender, "afk", false);
+ if ( !isSilent(sender) )
+ Utils.broadcast("§7 * ", Utils.getName(sender) + "§7 is no longer AFK", null);
+ }
+
+ public boolean isafk(CommandSender sender)
+ {
+ return DataManager.getState(sender, "afk");
+ }
+
+ public boolean isSilent(CommandSender sender)
+ {
+ return DataManager.getState(sender, "afk_silent");
+ }
+
+ public boolean isVanished(Player player)
+ {
+ return DataManager.getState(player, "vanished");
+ }
+
+ public void listenMove(boolean move)
+ {
+ this.move = move;
+ }
+
+ public void listenLook(boolean look)
+ {
+ this.look = look;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/BlockPlaceMods.java b/src/main/java/com/redstoner/modules/blockplacemods/BlockPlaceMods.java
new file mode 100644
index 0000000..6befbae
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/BlockPlaceMods.java
@@ -0,0 +1,206 @@
+package com.redstoner.modules.blockplacemods;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Listener;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.blockplacemods.mods.Mod;
+import com.redstoner.modules.blockplacemods.mods.ModAbstract;
+import com.redstoner.modules.blockplacemods.mods.ModToggledAbstract;
+import com.redstoner.utils.CommandException;
+import com.redstoner.utils.CommandMap;
+
+@Commands(CommandHolderType.None)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 1, compatible = 4)
+public final class BlockPlaceMods implements Module, Listener
+{
+ @Override
+ public boolean onEnable()
+ {
+ ModAbstract.registerAll(getLogger());
+ for (Mod mod : new ArrayList<>(ModAbstract.getMods().values()))
+ {
+ mod.registerListeners();
+ }
+ try
+ {
+ Map<String, org.bukkit.command.Command> commandMap = CommandMap.getCommandMap();
+ org.bukkit.command.Command command = new BlockPlaceModsCommand();
+ for (String alias : getCommandAliases())
+ {
+ commandMap.put(alias, command);
+ }
+ }
+ catch (ReflectiveOperationException ex)
+ {
+ ex.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void postEnable()
+ {
+ setPrefix("BPM");
+ }
+
+ @Override
+ public void onDisable()
+ {
+ for (Mod mod : ModAbstract.getMods().values())
+ {
+ mod.unregisterListeners();
+ }
+ try
+ {
+ Map<String, org.bukkit.command.Command> commandMap = CommandMap.getCommandMap();
+ for (String alias : getCommandAliases())
+ {
+ org.bukkit.command.Command command = commandMap.get(alias);
+ if (command != null && command.getClass() == BlockPlaceModsCommand.class)
+ {
+ commandMap.remove(alias);
+ }
+ }
+ }
+ catch (Exception ignored)
+ {}
+ }
+
+ private static String[] getCommandAliases()
+ {
+ String pluginName = Main.plugin.getName().toLowerCase();
+ // @noformat
+ return new String[]{"mod", pluginName + ":mod",
+ "set", pluginName + ":set",
+ "toggle", pluginName + ":toggle"
+ };
+ // @format
+ }
+
+ @Command(hook = "mod_empty")
+ public void onModEmptyCommand(CommandSender sender)
+ {
+ onModCommand(sender, "");
+ }
+
+ @Command(hook = "mod")
+ public void onModCommand(CommandSender sender, String input)
+ {
+ String[] args = new ArrayList<>(Arrays.asList(input.split(" "))).stream()
+ .filter(x -> x != null && !x.trim().isEmpty()).toArray(String[]::new);
+ String prefix = "";
+ String message;
+ try
+ {
+ if (args.length > 0)
+ {
+ Mod target = ModAbstract.getMod(args[0].toLowerCase());
+ if (target != null)
+ {
+ prefix += "&7[&2" + capitalize(target.getName()) + "&7]:&a ";
+ if (!(sender instanceof Player))
+ {
+ message = "&cYou must be a player to use any block place mod";
+ }
+ else
+ {
+ message = target.runCommand((Player) sender, Arrays.copyOfRange(args, 1, args.length));
+ }
+ }
+ else if (args[0].equalsIgnoreCase("help"))
+ {
+ message = commandHelp(sender, args);
+ }
+ else
+ {
+ message = "&cThat argument could not be recognized";
+ }
+ }
+ else
+ {
+ message = commandHelp(sender, args);
+ }
+ }
+ catch (CommandException ex)
+ {
+ message = " &c" + ex.getMessage();
+ }
+ catch (Throwable t)
+ {
+ message = " &cAn unexpected error occurred while executing this command.";
+ t.printStackTrace();
+ }
+ getLogger().message(sender, prefix + message);
+ }
+
+ private String commandHelp(CommandSender sender, String[] args)
+ {
+ StringBuilder result = new StringBuilder("§7BlockPlaceMods adds some redstone-centric utilities");
+ result.append("\n").append(ChatColor.GRAY.toString()).append("Available mods:");
+ List<Mod> mods = new ArrayList<>(new HashSet<>(ModAbstract.getMods().values()));
+ mods.sort(Comparator.<Mod> comparingInt(m -> ModToggledAbstract.class.isInstance(m) ? 1 : -1)
+ .thenComparing(Mod::getName));
+ for (Mod mod : mods)
+ {
+ result.append("\n").append(ChatColor.AQUA.toString()).append("/mod ").append(ChatColor.ITALIC.toString())
+ .append(mod.getName());
+ for (String alias : mod.getAliases())
+ {
+ result.append('|').append(alias);
+ }
+ result.append(ChatColor.GRAY.toString()).append(" - ").append(mod.getDescription());
+ }
+ return result.toString();
+ }
+
+ private static String capitalize(String modName)
+ {
+ if (modName.isEmpty())
+ {
+ return modName;
+ }
+ char first = modName.charAt(0);
+ if (first != (first = Character.toUpperCase(first)))
+ {
+ char[] result = modName.toCharArray();
+ result[0] = first;
+ return String.valueOf(result);
+ }
+ return modName;
+ }
+
+ private class BlockPlaceModsCommand extends org.bukkit.command.Command
+ {
+ public BlockPlaceModsCommand()
+ {
+ super("mod");
+ String[] aliases = getCommandAliases();
+ setAliases(Arrays.asList(Arrays.copyOfRange(aliases, 1, aliases.length)));
+ }
+
+ @Override
+ public boolean execute(CommandSender sender, String label, String[] args)
+ {
+ onModCommand(sender, String.join(" ", args));
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/Mod.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/Mod.java
new file mode 100644
index 0000000..9a2fcad
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/Mod.java
@@ -0,0 +1,24 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.entity.Player;
+
+import com.redstoner.utils.CommandException;
+
+import java.util.Set;
+
+public interface Mod
+{
+ String getName();
+
+ String getDescription();
+
+ Set<String> getAliases();
+
+ Object getDefault();
+
+ String runCommand(Player sender, String[] args) throws CommandException;
+
+ void registerListeners();
+
+ void unregisterListeners();
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModAbstract.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModAbstract.java
new file mode 100644
index 0000000..5a383d8
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModAbstract.java
@@ -0,0 +1,94 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryType;
+
+import com.redstoner.misc.Main;
+import com.redstoner.modules.ModuleLogger;
+import com.redstoner.modules.datamanager.DataManager;
+
+public abstract class ModAbstract implements Mod, Listener
+{
+ private static final Map<String, Mod> mods = new HashMap<>();
+ private final String name;
+ private final Set<String> aliases;
+ private static ModuleLogger logger;
+
+ public static Map<String, Mod> getMods()
+ {
+ return Collections.unmodifiableMap(mods);
+ }
+
+ public static Mod getMod(String name)
+ {
+ return mods.get(name);
+ }
+
+ public static void registerMod(Mod mod)
+ {
+ mods.put(mod.getName(), mod);
+ for (String alias : mod.getAliases())
+ {
+ mods.putIfAbsent(alias, mod);
+ }
+ }
+
+ public static void registerAll(final ModuleLogger logger)
+ {
+ ModAbstract.logger = logger;
+ registerMod(new ModToggledCauldron());
+ registerMod(new ModToggledPiston());
+ registerMod(new ModToggledObserver());
+ registerMod(new ModToggledStep());
+ registerMod(new ModToggledTorch());
+ registerMod(new ModInventory("dropper", InventoryType.DROPPER));
+ registerMod(new ModInventory("furnace", InventoryType.FURNACE));
+ registerMod(new ModInventory("hopper", InventoryType.HOPPER));
+ }
+
+ public ModAbstract(String name)
+ {
+ this.name = Objects.requireNonNull(name);
+ this.aliases = new HashSet<>(2);
+ logger.info("Loaded mod " + name);
+ }
+
+ @Override
+ public String getName()
+ {
+ return name;
+ }
+
+ @Override
+ public Set<String> getAliases()
+ {
+ return aliases;
+ }
+
+ @Override
+ public void registerListeners()
+ {
+ Bukkit.getPluginManager().registerEvents(this, Main.plugin);
+ }
+
+ @Override
+ public void unregisterListeners()
+ {
+ HandlerList.unregisterAll(this);
+ }
+
+ protected void reset(Player player)
+ {
+ DataManager.removeData(player.getUniqueId().toString(), "BlockPlaceMods", getName());
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModInventory.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModInventory.java
new file mode 100644
index 0000000..c6e483e
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModInventory.java
@@ -0,0 +1,195 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import com.redstoner.modules.datamanager.DataManager;
+import com.redstoner.utils.CommandException;
+import com.redstoner.utils.ItemProperties;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.block.BlockState;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.InventoryHolder;
+import org.bukkit.inventory.ItemStack;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import java.util.Arrays;
+
+public class ModInventory extends ModAbstract
+{
+ protected InventoryType inventoryType;
+
+ public ModInventory(String name, InventoryType inventoryType)
+ {
+ super(name);
+ this.inventoryType = inventoryType;
+ }
+
+ private static int highestUsedIndex(ItemStack[] items)
+ {
+ for (int i = items.length - 1; i >= 0; i--)
+ {
+ if (items[i] != null)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "Controls " + inventoryType.name().toLowerCase() + " placement content";
+ }
+
+ @Override
+ public String runCommand(Player sender, String[] args) throws CommandException
+ {
+ if (args.length > 0)
+ {
+ if (args[0].equalsIgnoreCase("clear"))
+ {
+ reset(sender);
+ return "Reset data successfully";
+ }
+ try
+ {
+ int slot = Integer.parseInt(args[0]);
+ if (slot >= inventoryType.getDefaultSize())
+ {
+ throw new CommandException(
+ "Slot number " + slot + " is too high for " + inventoryType.toString().toLowerCase() + "s");
+ }
+ if (slot < 0)
+ {
+ throw new CommandException("Slot number " + slot + " is negative");
+ }
+ // Set the stored item to the item in the sender's hand
+ ItemStack item = sender.getInventory().getItemInMainHand();
+ if (item == null || item.getType() == Material.AIR || item.getAmount() == 0)
+ {
+ // Remove the item.
+ // Set item to null to ensure correct itemName below.
+ item = null;
+ if (present(sender))
+ {
+ set(sender, slot, null);
+ }
+ }
+ else
+ {
+ set(sender, slot, item);// don't need to clone because the reference isn't kept
+ }
+ String itemName = item == null ? "nothing"
+ : item.getAmount() + " " + item.getType().toString().toLowerCase().replace("_", "");
+ return "Set the item in slot " + slot + " to " + itemName;
+ }
+ catch (NumberFormatException ex)
+ {
+ if (!args[0].equalsIgnoreCase("help"))
+ {
+ throw new CommandException("Expected a number indicating the slot that you want to set");
+ }
+ }
+ }
+ StringBuilder message = new StringBuilder();
+ message.append(" &a### &3Container Mod&a Help ###\n");
+ message.append("&7").append(getDescription()).append('\n');
+ message.append("&6/mod ").append(getName().toLowerCase())
+ .append("&o <slot> &bsets the item in slot to your hand\n");
+ message.append("&6/mod ").append(getName().toLowerCase()).append("&o clear &bclears the data\n");
+ message.append("&6/mod ").append(getName().toLowerCase()).append("&o help &bshows this help page\n");
+ return message.toString();
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ if (present(event.getPlayer()) && event.getPlayer().getGameMode() == GameMode.CREATIVE)
+ {
+ BlockState state = event.getBlock().getState();
+ if (state instanceof InventoryHolder)
+ {
+ Inventory inv = ((InventoryHolder) state).getInventory();
+ if (inv.getType() == inventoryType)
+ {
+ ItemStack[] data = get(event.getPlayer());
+ inv.setContents(data);
+ state.update();
+ }
+ }
+ }
+ }
+
+ protected ItemStack[] get(Player player)
+ {
+ Object obj = DataManager.getData(player.getUniqueId().toString(), "BlockPlaceMods", getName());
+ if (obj == null)
+ return getDefault();
+ JSONArray array = (JSONArray) obj;
+ ItemStack[] items = new ItemStack[Math.min(inventoryType.getDefaultSize(), array.size())];
+ for (int i = 0, n = items.length; i < n; i++)
+ {
+ Object obj2 = array.get(i);
+ if (obj2 instanceof JSONObject)
+ { // if null, items[i] remains null
+ items[i] = new ItemProperties().loadFrom((JSONObject) obj2).toItemStack();
+ }
+ }
+ return items;
+ }
+
+ protected void set(Player player, int index, ItemStack item)
+ {
+ ItemStack[] data = get(player);
+ if (item == null)
+ {
+ if (index < data.length)
+ {
+ data[index] = null;
+ }
+ }
+ else
+ {
+ if (index >= data.length)
+ {
+ data = Arrays.copyOf(data, index + 1);
+ }
+ data[index] = item;
+ }
+ set(player, data);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void set(Player player, ItemStack[] data)
+ {
+ if (highestUsedIndex(data) == -1)
+ reset(player);
+ else
+ {
+ JSONArray array = new JSONArray();
+ for (int i = 0, n = highestUsedIndex(data); i < n; i++)
+ {
+ ItemStack item = data[i];
+ array.add(item == null ? null : new ItemProperties(item).toJSONObject());
+ }
+ DataManager.setData(player.getUniqueId().toString(), "BlockPlaceMods", getName(), array);
+ }
+ }
+
+ protected boolean present(Player player)
+ {
+ return get(player) != null;
+ }
+
+ @Override
+ public ItemStack[] getDefault()
+ {
+ return new ItemStack[0];
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledAbstract.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledAbstract.java
new file mode 100644
index 0000000..b9b2a7c
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledAbstract.java
@@ -0,0 +1,80 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import com.redstoner.modules.datamanager.DataManager;
+import com.redstoner.utils.CommandException;
+import org.bukkit.entity.Player;
+
+public abstract class ModToggledAbstract extends ModAbstract
+{
+ protected boolean enabledByDefault;
+
+ public ModToggledAbstract(String name, boolean enabledByDefault) {
+ super(name);
+ this.enabledByDefault = enabledByDefault;
+ }
+
+ @Override
+ public Boolean getDefault() {
+ return enabledByDefault;
+ }
+
+ protected boolean hasEnabled(Player player)
+ {
+ return (boolean) DataManager.getOrDefault(player.getUniqueId().toString(), "BlockPlaceMods", getName(),
+ enabledByDefault);
+ }
+
+ protected boolean setEnabled(Player sender, boolean enabled)
+ {
+ if (enabled == hasEnabled(sender))
+ return false;
+ if (enabled == enabledByDefault)
+ reset(sender);
+ else
+ DataManager.setData(sender.getUniqueId().toString(), "BlockPlaceMods", getName(), enabled);
+ return true;
+ }
+
+ @Override
+ public String runCommand(Player sender, String[] args) throws CommandException
+ {
+ if (args.length == 0 || args[0].equalsIgnoreCase("toggle"))
+ {
+ boolean enabled = hasEnabled(sender);
+ setEnabled(sender, !enabled);
+ return !enabled ? "Enabled" : "Disabled";
+ }
+ if (args[0].equalsIgnoreCase("help"))
+ {
+ StringBuilder message = new StringBuilder();
+ message.append(" &a### &3Toggled Mod&a Help ###");
+ message.append("\n&7").append(getDescription());
+ message.append("\n&6/mod ").append(getName()).append("&o (toggle) &btoggles state");
+ message.append("\n&6/mod ").append(getName()).append("&o on/off &bsets state");
+ message.append("\n&6/mod ").append(getName()).append("&o help &bshows this help page");
+ return message.toString();
+ }
+ final boolean enable;
+ switch (args[0].toLowerCase())
+ {
+ case "on":
+ case "enable":
+ case "true":
+ enable = true;
+ break;
+ case "off":
+ case "disable":
+ case "false":
+ enable = false;
+ break;
+ default:
+ throw new CommandException("Input '" + args[0] + "' was not understood. "
+ + "Use one of: \non, enable, true, off, disable, false.");
+ }
+ if (!setEnabled(sender, enable))
+ {
+ throw new CommandException("Was already " + (enable ? "enabled" : "disabled"));
+ }
+ return enable ? "Enabled" : "Disabled";
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledCauldron.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledCauldron.java
new file mode 100644
index 0000000..669f093
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledCauldron.java
@@ -0,0 +1,49 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+
+public class ModToggledCauldron extends ModToggledAbstract
+{
+ public ModToggledCauldron()
+ {
+ super("cauldron", false);
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "If active, placed cauldrons are filled, and they cycle on shiftless right click with redstone or fist";
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void onPlayerInteract(PlayerInteractEvent event)
+ {
+ if (event.getAction() == Action.RIGHT_CLICK_BLOCK && !event.getPlayer().isSneaking()
+ && event.getClickedBlock().getType() == Material.CAULDRON && hasEnabled(event.getPlayer())
+ && (event.getPlayer().getGameMode() == GameMode.CREATIVE)
+ && (event.getPlayer().getInventory().getItemInMainHand().getType() == Material.AIR))
+ {
+ Block block = event.getClickedBlock();
+ block.setData((byte) ((block.getData() - 1) & 0x3));
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ if (event.getBlock().getType() == Material.CAULDRON && !event.getPlayer().isSneaking()
+ && hasEnabled(event.getPlayer()) && (event.getPlayer().getGameMode() == GameMode.CREATIVE))
+ {
+ event.getBlock().setData((byte) 3);
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledLogPlaceAbstract.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledLogPlaceAbstract.java
new file mode 100644
index 0000000..17c414b
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledLogPlaceAbstract.java
@@ -0,0 +1,40 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.GameMode;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+/**
+ * A mod that makes placement of directional blocks act the way placement of logs does normally.
+ * Quartz pillar placement works like this too.
+ *
+ * Placed blocks face the block you clicked to place them.
+ */
+public abstract class ModToggledLogPlaceAbstract extends ModToggledAbstract {
+
+ protected ModToggledLogPlaceAbstract(String name, boolean enabledByDefault) {
+ super(name, enabledByDefault);
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ Player player = event.getPlayer();
+ Block block;
+ if (hasEnabled(player) && !player.isSneaking() && player.getGameMode() == GameMode.CREATIVE
+ && isApplicableToPlacedBlock(block = event.getBlock()))
+ {
+ block.setData((byte) getBlockDataForFacing(block.getFace(event.getBlockAgainst())));
+ }
+ }
+
+ protected abstract int getBlockDataForFacing(BlockFace direction);
+
+ protected abstract boolean isApplicableToPlacedBlock(Block block);
+
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledObserver.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledObserver.java
new file mode 100644
index 0000000..8084bf4
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledObserver.java
@@ -0,0 +1,43 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+
+public class ModToggledObserver extends ModToggledLogPlaceAbstract {
+
+ protected ModToggledObserver() {
+ super("observer", false);
+ }
+
+ @Override
+ public String getDescription() {
+ return "If active, observers face the block you place them against";
+ }
+
+ @Override
+ protected boolean isApplicableToPlacedBlock(Block block) {
+ return block.getType() == Material.OBSERVER;
+ }
+
+ @Override
+ protected int getBlockDataForFacing(BlockFace direction) {
+ switch (direction) {
+ case UP:
+ return 0;
+ default:
+ case DOWN:
+ return 1;
+ case SOUTH:
+ return 2;
+ case NORTH:
+ return 3;
+ case EAST:
+ return 4;
+ case WEST:
+ return 5;
+ }
+ }
+
+
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledPiston.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledPiston.java
new file mode 100644
index 0000000..29e810c
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledPiston.java
@@ -0,0 +1,46 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+
+public class ModToggledPiston extends ModToggledLogPlaceAbstract
+{
+ public ModToggledPiston()
+ {
+ super("piston", false);
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "If active, pistons face the block you place them against";
+ }
+
+ @Override
+ protected boolean isApplicableToPlacedBlock(Block block) {
+ Material type = block.getType();
+ return type == Material.PISTON_BASE || type == Material.PISTON_STICKY_BASE;
+ }
+
+ @Override
+ protected int getBlockDataForFacing(BlockFace direction) {
+ switch (direction)
+ {
+ default:
+ case DOWN:
+ return 0;
+ case UP:
+ return 1;
+ case NORTH:
+ return 2;
+ case SOUTH:
+ return 3;
+ case WEST:
+ return 4;
+ case EAST:
+ return 5;
+ }
+ }
+
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledStep.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledStep.java
new file mode 100644
index 0000000..fe42fa4
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledStep.java
@@ -0,0 +1,40 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import org.bukkit.Material;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+public class ModToggledStep extends ModToggledAbstract
+{
+ public ModToggledStep()
+ {
+ super("step", true);
+ getAliases().add("slab");
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "If active, placed steps will always turn upside-down";
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ if (isStep(event.getBlock().getType()) && !event.getPlayer().isSneaking() && hasEnabled(event.getPlayer()))
+ {
+ byte data = event.getBlock().getData();
+ if (data != (data |= 0x8))
+ {
+ event.getBlock().setData(data);
+ }
+ }
+ }
+
+ private boolean isStep(Material block)
+ {
+ return block == Material.STEP || block == Material.STONE_SLAB2;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledTorch.java b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledTorch.java
new file mode 100644
index 0000000..188bce2
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/blockplacemods/mods/ModToggledTorch.java
@@ -0,0 +1,91 @@
+package com.redstoner.modules.blockplacemods.mods;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.bukkit.Bukkit;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.block.BlockPlaceEvent;
+
+import com.redstoner.misc.Main;
+
+public class ModToggledTorch extends ModToggledAbstract
+{
+ private final Set<Block> torchesPlaced = new HashSet<>();
+
+ public ModToggledTorch()
+ {
+ super("torch", true);
+ Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.plugin, this::updateTorches, 2, 2);
+ }
+
+ @Override
+ public String getDescription()
+ {
+ return "If active, redstone torches placed on a redstone block disappear quickly";
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onBlockPlace(BlockPlaceEvent event)
+ {
+ final Player player = event.getPlayer();
+ if (!player.isSneaking() && player.getGameMode() == GameMode.CREATIVE && hasEnabled(player)
+ && event.getBlock().getType() == Material.REDSTONE_TORCH_ON)
+ {
+ if (isAttachedToRedstoneBlock(event.getBlock()))
+ {
+ torchesPlaced.add(event.getBlock());
+ }
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private boolean isAttachedToRedstoneBlock(Block block)
+ {
+ BlockFace towardsAgainst = getFaceTowardsBlockAgainst(block.getData());
+ return towardsAgainst != null && block.getRelative(towardsAgainst).getType() == Material.REDSTONE_BLOCK;
+ }
+
+ private BlockFace getFaceTowardsBlockAgainst(byte data)
+ {
+ switch (data)
+ {
+ case 1:
+ return BlockFace.WEST;
+ case 2:
+ return BlockFace.EAST;
+ case 3:
+ return BlockFace.NORTH;
+ case 4:
+ return BlockFace.SOUTH;
+ case 5:
+ return BlockFace.DOWN;
+ default:
+ return null;
+ }
+ }
+
+ private void updateTorches()
+ {
+ for (Iterator<Block> it = torchesPlaced.iterator(); it.hasNext();)
+ {
+ Block block = it.next();
+ if (block.getType() == Material.REDSTONE_TORCH_OFF)
+ {
+ block.setType(Material.AIR);
+ it.remove();
+ }
+ else if (block.getType() != Material.REDSTONE_TORCH_ON || !isAttachedToRedstoneBlock(block))
+ {
+ it.remove();
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/buildchat/BuildChat.cmd b/src/main/java/com/redstoner/modules/buildchat/BuildChat.cmd
new file mode 100644
index 0000000..ddd7d77
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/buildchat/BuildChat.cmd
@@ -0,0 +1,42 @@
+command bc {
+ [string:message...] {
+ help Sends a message in BuildTeam Chat;
+ perm utils.bc;
+ run bc_msg message;
+ }
+}
+command bcn {
+ [string:name] [string:message...] {
+ help Sends a message in BuildTeam Chat;
+ perm utils.bc;
+ type console;
+ run bcn_msg name message;
+ }
+}
+
+command bckey {
+ [string:key] {
+ help Sets your BuildTeam Chat key;
+ perm utils.bc;
+ type player;
+ run setbckey key;
+ }
+}
+
+command bct {
+ on {
+ help Turns on bct;
+ perm utils.bc;
+ run bct_on;
+ }
+ off {
+ help Turns off bct;
+ perm utils.bc;
+ run bct_off;
+ }
+ [empty] {
+ help toggles BuildTeam Chat;
+ perm utils.bc;
+ run bct;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/buildchat/BuildChat.java b/src/main/java/com/redstoner/modules/buildchat/BuildChat.java
new file mode 100644
index 0000000..4ea0779
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/buildchat/BuildChat.java
@@ -0,0 +1,207 @@
+package com.redstoner.modules.buildchat;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.BroadcastFilter;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+
+/** BuildTeamChat module. Allows the build team to chat privately using /bc \<message\> as well as a one char prefix or a toggle.
+ *
+ * @author Pepich */
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class BuildChat implements Module, Listener
+{
+ private static final char defaultKey = ';';
+ private static final File keysLocation = new File(Main.plugin.getDataFolder(), "buildchat_keys.json");
+ private ArrayList<UUID> bctoggled;
+ private static JSONObject keys;
+
+ @Override
+ public boolean onEnable()
+ {
+ keys = JsonManager.getObject(keysLocation);
+ if (keys == null)
+ {
+ keys = new JSONObject();
+ saveKeys();
+ }
+ bctoggled = new ArrayList<>();
+ return true;
+ }
+
+ @Command(hook = "bc_msg")
+ public boolean bcSay(CommandSender sender, String message)
+ {
+ String name;
+ if (sender instanceof Player)
+ name = ((Player) sender).getDisplayName();
+ else
+ name = sender.getName();
+ Utils.broadcast("§8[§cBC§8] §9" + name + "§8: §b", message, new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return recipient.hasPermission("utils.bc");
+ }
+ });
+ return true;
+ }
+
+ @Command(hook = "bcn_msg")
+ public boolean bcnSay(CommandSender sender, String name, String message)
+ {
+ Utils.broadcast("§8[§cBC§8] §9" + name + "§8: §b", message, new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return recipient.hasPermission("utils.bc");
+ }
+ });
+ return true;
+ }
+
+ /** Let's a Player toggle their auto-cg status to allow for automatically sending chat messages to their chatgroup.
+ *
+ * @param sender the issuer of the command.
+ * @param _void ignored.
+ * @return true. */
+ @Command(hook = "bct")
+ public boolean bcToggleCommand(CommandSender sender)
+ {
+ if (bctoggled.contains(((Player) sender).getUniqueId()))
+ {
+ bctoggled.remove(((Player) sender).getUniqueId());
+ getLogger().message(sender, "BCT now §cdisabled");
+ }
+ else
+ {
+ bctoggled.add(((Player) sender).getUniqueId());
+ getLogger().message(sender, "BCT now §aenabled");
+ }
+ return true;
+ }
+
+ /** Let's a Player toggle their auto-cg status to allow for automatically sending chat messages to their chatgroup.
+ *
+ * @param sender the issuer of the command.
+ * @return true. */
+ @Command(hook = "bct_on")
+ public boolean bcToggleOnCommand(CommandSender sender)
+ {
+ if (!bctoggled.contains(((Player) sender).getUniqueId()))
+ {
+ bctoggled.add(((Player) sender).getUniqueId());
+ getLogger().message(sender, "BCT now §aenabled");
+ }
+ else
+ getLogger().message(sender, "BCT was already enabled");
+ return true;
+ }
+
+ /** Let's a Player toggle their auto-cg status to allow for automatically sending chat messages to their chatgroup.
+ *
+ * @param sender the issuer of the command.
+ * @return true. */
+ @Command(hook = "bct_off")
+ public boolean bcToggleOffCommand(CommandSender sender)
+ {
+ if (bctoggled.remove(((Player) sender).getUniqueId()))
+ getLogger().message(sender, "BCT now §cdisabled");
+ else
+ getLogger().message(sender, "BCT was already disabled");
+ return true;
+ }
+
+ /** Deals with chat events to allow for bckeys and bctoggle.
+ *
+ * @param event the chat event containing the player and the message. */
+ @EventHandler
+ public void onPlayerChat(AsyncPlayerChatEvent event)
+ {
+ Player player = event.getPlayer();
+ if (!player.hasPermission("utils.bc"))
+ return;
+ if (event.getMessage().startsWith(getKey(player)))
+ {
+ event.setCancelled(true);
+ bcSay(event.getPlayer(), event.getMessage().replaceFirst(Pattern.quote(getKey(player)), ""));
+ }
+ else if (bctoggled.contains(event.getPlayer().getUniqueId()))
+ {
+ event.setCancelled(true);
+ bcSay(event.getPlayer(), event.getMessage());
+ }
+ }
+
+ /** Sets the bckey of a Player.
+ *
+ * @param sender the issuer of the command.
+ * @param key the key to be set. Set to NULL or "" to get your current key.
+ * @return true. */
+ @SuppressWarnings("unchecked")
+ @Command(hook = "setbckey")
+ public boolean setBcKey(CommandSender sender, String key)
+ {
+ if (key.length() > 1)
+ {
+ getLogger().message(sender, true,
+ "Could not set your key to §6" + key + " §7, it can be at most one char.");
+ return true;
+ }
+ if (key == null || key.length() == 0)
+ {
+ getBcKey(sender);
+ return true;
+ }
+ getLogger().message(sender, "Set your key to §6" + key);
+ keys.put(((Player) sender).getUniqueId().toString(), key + "");
+ saveKeys();
+ return true;
+ }
+
+ /** This method will find the ChatgGroup key of any player.
+ *
+ * @param player the player to get the key from.
+ * @return the key. */
+ public static String getKey(Player player)
+ {
+ String key = (String) keys.get(player.getUniqueId().toString());
+ return (key == null ? "" + defaultKey : key);
+ }
+
+ /** Prints a Players bckey to their chat.
+ *
+ * @param sender the issuer of the command. */
+ public void getBcKey(CommandSender sender)
+ {
+ getLogger().message(sender, "Your current bckey is §6" + getKey((Player) sender));
+ }
+
+ /** Saves the keys. */
+ private void saveKeys()
+ {
+ JsonManager.save(keys, keysLocation);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/buildteam/BuildTeam.cmd b/src/main/java/com/redstoner/modules/buildteam/BuildTeam.cmd
new file mode 100644
index 0000000..d4f3303
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/buildteam/BuildTeam.cmd
@@ -0,0 +1,22 @@
+command teleport {
+ alias tp;
+ alias tele;
+ [string:player...] {
+ run teleport player;
+ }
+ type player;
+}
+
+command team_add {
+ [string:player] {
+ run team_add player;
+ perm utils.buildteam.manage;
+ }
+}
+
+command team_remove {
+ [string:player] {
+ run team_remove player;
+ perm utils.buildteam.manage;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/buildteam/BuildTeam.java b/src/main/java/com/redstoner/modules/buildteam/BuildTeam.java
new file mode 100644
index 0000000..986b41c
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/buildteam/BuildTeam.java
@@ -0,0 +1,56 @@
+package com.redstoner.modules.buildteam;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 0, compatible = 4)
+public class BuildTeam implements Module
+{
+ @Command(hook = "teleport")
+ public boolean teleport(CommandSender sender, String target_name)
+ {
+ final Player player = (Player) sender;
+ final Player target = Bukkit.getPlayer(target_name);
+ if (target == null || !player.hasPermission("utils.buildteam.teleport")
+ || !target.getLocation().getWorld().getName().equals("BuildTeam"))
+ {
+ player.performCommand("essentials:tp " + target_name);
+ return true;
+ }
+ player.teleport(target);
+ getLogger().message(sender, "Teleported you to &e" + target.getDisplayName() + "&7!");
+ return true;
+ }
+
+ @Command(hook = "team_add")
+ public boolean add(CommandSender sender, String target_name)
+ {
+ if (!target_name.matches("^\\w{2,16}$"))
+ {
+ getLogger().message(sender, true, "This doesn't look like a valid playername!");
+ return true;
+ }
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "pex user " + target_name + " group add +buildteam");
+ return true;
+ }
+
+ @Command(hook = "team_remove")
+ public boolean remove(CommandSender sender, String target_name)
+ {
+ if (!target_name.matches("^\\w{2,16}$"))
+ {
+ getLogger().message(sender, true, "This doesn't look like a valid playername!");
+ return true;
+ }
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "pex user " + target_name + " group remove +buildteam");
+ return true;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/chat/Chat.cmd b/src/main/java/com/redstoner/modules/chat/Chat.cmd
new file mode 100644
index 0000000..3091609
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/chat/Chat.cmd
@@ -0,0 +1,81 @@
+command me {
+ perm utils.me;
+ [string:text...] {
+ help /me's in chat.;
+ run me text;
+ }
+}
+command action {
+ perm utils.action;
+ [string:text...] {
+ help /action's in chat.;
+ run action text;
+ }
+}
+command chat {
+ alias speak;
+ [string:message...] {
+ perm utils.chat;
+ run chat message;
+ help A way to speak in normal chat with normal formatting if you have ACT or CGT on.;
+ }
+}
+command chatn {
+ alias speakn;
+ [string:name] [string:message...] {
+ perm utils.chatn;
+ run chatn name message;
+ help A way to speak in normal chat with normal formatting for console users.;
+ }
+}
+command shrug {
+ [string:message...] {
+ perm utils.shrug;
+ run shrug message;
+ help Appends the shrug emoticon to the end of your message.;
+ }
+ [empty] {
+ perm utils.shrug;
+ run shrugnoarg;
+ help Just the shrug emoticon.;
+ }
+}
+command say {
+ [string:message...] {
+ perm utils.say;
+ run say message;
+ help A replacement for the default say command to make the format be more consistant.;
+ }
+}
+command sayn {
+ [string:name] [string:message...] {
+ perm utils.sayn;
+ type console;
+ run sayn name message;
+ help A replacement for the default say command to make the format be more consistant.;
+ }
+}
+
+command mute {
+ [string:player] {
+ perm utils.chat.admin;
+ run mute player;
+ help Mutes a player.;
+ }
+}
+
+command print {
+ [string:message...] {
+ perm utils.print;
+ run print message;
+ help A way to just print something in to chat with all the formatting things a user has.;
+ }
+}
+
+command unmute {
+ [string:player] {
+ perm utils.chat.admin;
+ run unmute player;
+ help Unmutes a player.;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/chat/Chat.java b/src/main/java/com/redstoner/modules/chat/Chat.java
new file mode 100644
index 0000000..1c7f8a1
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/chat/Chat.java
@@ -0,0 +1,215 @@
+package com.redstoner.modules.chat;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.command.ConsoleCommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.BroadcastFilter;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+import com.redstoner.modules.ignore.Ignore;
+
+import net.nemez.chatapi.ChatAPI;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 1, compatible = 4)
+public class Chat implements Module, Listener
+{
+ private final Map<String, String> defaults = new HashMap<>();
+
+ public Chat()
+ {
+ defaults.put("chat", " %n §7→§r %m");
+ defaults.put("me", " §7- %n §7⇦ %m");
+ defaults.put("action", " §7- %n §7⇦ %m");
+ defaults.put("say", " §7[§9%n§7]:§r %m");
+ defaults.put("shrug", " %n §7→§r %m ¯\\_(ツ)_/¯");
+ defaults.put("print", "%m");
+ }
+
+ @Override
+ public void firstLoad()
+ {
+ Module.super.firstLoad();
+ DataManager.setConfig("chat", defaults.get("chat"));
+ DataManager.setConfig("me", defaults.get("me"));
+ DataManager.setConfig("action", defaults.get("action"));
+ DataManager.setConfig("say", defaults.get("say"));
+ DataManager.setConfig("shrug", defaults.get("shrug"));
+ DataManager.setConfig("print", defaults.get("print"));
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onPlayerChat(AsyncPlayerChatEvent event)
+ {
+ if (event.isCancelled())
+ return;
+ Player player = event.getPlayer();
+ String message = event.getMessage();
+ event.setCancelled(true);
+ broadcastFormatted("chat", player, message, event);
+ }
+
+ @Command(hook = "me")
+ public boolean me(CommandSender sender, String message)
+ {
+ broadcastFormatted("me", sender, message);
+ return true;
+ }
+
+ @Command(hook = "chat")
+ public boolean chat(CommandSender sender, String message)
+ {
+ broadcastFormatted("chat", sender, message);
+ return true;
+ }
+
+ @Command(hook = "chatn")
+ public boolean chatn(CommandSender sender, String name, String message)
+ {
+ broadcastFormatted("chat", sender, message, name);
+ return true;
+ }
+
+ @Command(hook = "action")
+ public boolean action(CommandSender sender, String message)
+ {
+ broadcastFormatted("action", sender, message);
+ return true;
+ }
+
+ @Command(hook = "say")
+ public boolean say(CommandSender sender, String message)
+ {
+ String name;
+ if (sender instanceof Player)
+ name = ((Player) sender).getName();
+ else
+ name = "§9CONSOLE";
+ broadcastFormatted("say", sender, message, name);
+ return true;
+ }
+
+ @Command(hook = "sayn")
+ public boolean say(CommandSender sender, String name, String message)
+ {
+ broadcastFormatted("say", sender, message, name);
+ return true;
+ }
+
+ @Command(hook = "shrug")
+ public boolean shrug(CommandSender sender, String message)
+ {
+ broadcastFormatted("shrug", sender, message);
+ return true;
+ }
+
+ @Command(hook = "shrugnoarg")
+ public boolean shrug(CommandSender sender)
+ {
+ broadcastFormatted("shrug", sender, "");
+ return true;
+ }
+
+ @Command(hook = "print")
+ public boolean print(CommandSender sender, String message)
+ {
+ broadcastFormatted("print", sender, message);
+ return true;
+ }
+
+ @Command(hook = "mute")
+ public boolean mute(CommandSender sender, String player)
+ {
+ Player p = Bukkit.getPlayer(player);
+ if (p == null)
+ {
+ getLogger().message(sender, true, "That player couldn't be found!");
+ return true;
+ }
+ DataManager.setData(p, "muted", true);
+ getLogger().message(sender, "Muted player &e" + Utils.getName(p) + "&7!");
+ getLogger().message(p, "You have been &cmuted&7!");
+ return true;
+ }
+
+ @Command(hook = "unmute")
+ public boolean unmute(CommandSender sender, String player)
+ {
+ Player p = Bukkit.getPlayer(player);
+ if (p == null)
+ {
+ getLogger().message(sender, true, "That player couldn't be found!");
+ return true;
+ }
+ DataManager.setData(p, "muted", false);
+ getLogger().message(sender, "Unmuted player &e" + Utils.getName(p) + "&7!");
+ getLogger().message(p, "You have been &aunmuted&7!");
+ return true;
+ }
+
+ public boolean broadcastFormatted(String format, CommandSender sender, String message)
+ {
+ return broadcastFormatted(format, sender, message, Utils.getName(sender), null);
+ }
+
+ public boolean broadcastFormatted(String format, CommandSender sender, String message, String name)
+ {
+ return broadcastFormatted(format, sender, message, name, null);
+ }
+
+ public boolean broadcastFormatted(String format, CommandSender sender, String message, AsyncPlayerChatEvent event)
+ {
+ return broadcastFormatted(format, sender, message, Utils.getName(sender), event);
+ }
+
+ public boolean broadcastFormatted(String format, CommandSender sender, String message, String name,
+ AsyncPlayerChatEvent event)
+ {
+ if ((boolean) DataManager.getOrDefault(sender, "muted", false))
+ {
+ getLogger().message(sender, true, "You have been muted!");
+ getLogger().info(" &7User &e" + Utils.getName(sender) + " &7tried to &e" + format + " &7(&e" + message
+ + "&7) while being &cmuted&7.");
+ return false;
+ }
+ String raw = (String) DataManager.getConfigOrDefault(format, defaults.get(format));
+ String formatted = raw.replace("%n", name).replace("%m", message);
+ Utils.broadcast("", ChatAPI.colorify(sender, formatted),
+ wrap(ModuleLoader.exists("Ignore") ? Ignore.getIgnoredBy(sender) : null, event));
+ return true;
+ }
+
+ public BroadcastFilter wrap(BroadcastFilter filter, AsyncPlayerChatEvent event)
+ {
+ if (event == null)
+ return filter;
+ else
+ return new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ if (recipient instanceof ConsoleCommandSender)
+ return true;
+ return filter.sendTo(recipient) && event.getRecipients().contains(recipient);
+ }
+ };
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/chatalias/Chatalias.cmd b/src/main/java/com/redstoner/modules/chatalias/Chatalias.cmd
new file mode 100644
index 0000000..8af4bb6
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/chatalias/Chatalias.cmd
@@ -0,0 +1,16 @@
+command alias {
+ add [flag:-r] [string:keyword] [string:replacement...] {
+ help Adds a new alias. Set -r to make it a regex-alias.;
+ run addalias -r keyword replacement;
+ }
+ del [flag:-r] [string:keyword] {
+ help Deletes an alias. -r indicates if it was a regex-alias.;
+ run delalias -r keyword;
+ }
+ list {
+ help Lists your aliases.;
+ run listaliases;
+ }
+ perm utils.alias;
+ type player;
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/chatalias/Chatalias.java b/src/main/java/com/redstoner/modules/chatalias/Chatalias.java
new file mode 100644
index 0000000..eb13b4d
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/chatalias/Chatalias.java
@@ -0,0 +1,317 @@
+package com.redstoner.modules.chatalias;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.permissions.PermissionAttachmentInfo;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+
+import net.nemez.chatapi.ChatAPI;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Chatalias implements Module, Listener
+{
+ private final String[] commands = new String[] {"e?r", "e?m .+?", "e?t", "e?w", "e?msg .+?", "e?message .+?",
+ "e?whisper .+?", "e?me", "cgsay", "ac", "bc", "say", "sayn .+?", "chat", "shrug", "action"};
+ private JSONObject aliases = new JSONObject();
+
+ @Override
+ public boolean onEnable()
+ {
+ for (Player p : Bukkit.getOnlinePlayers())
+ {
+ loadAliases(p.getUniqueId());
+ }
+ return true;
+ }
+
+ @Override
+ public void onDisable()
+ {
+ for (Object key : aliases.keySet())
+ {
+ UUID uuid = UUID.fromString((String) key);
+ saveAliases(uuid);
+ }
+ }
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event)
+ {
+ loadAliases(event.getPlayer().getUniqueId());
+ }
+
+ @EventHandler
+ public void onPlayerLeave(PlayerQuitEvent event)
+ {
+ aliases.remove(event.getPlayer().getUniqueId().toString());
+ }
+
+ @SuppressWarnings("unchecked")
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onPlayerChat(AsyncPlayerChatEvent event)
+ {
+ Player player = event.getPlayer();
+ UUID uuid = player.getUniqueId();
+ if (!aliases.containsKey(uuid.toString()))
+ {
+ loadAliases(player.getUniqueId());
+ if (!aliases.containsKey(uuid.toString()))
+ return;
+ }
+ JSONObject playerAliases = (JSONObject) aliases.get(uuid.toString());
+ boolean changed = false;
+ for (Object key : playerAliases.keySet())
+ {
+ String keyword = (String) key;
+ String replacement = (String) playerAliases.get(key);
+ if (keyword.startsWith("R: "))
+ {
+ keyword = keyword.replace("R: ", "");
+ event.setMessage(event.getMessage().replaceAll(keyword, replacement));
+ }
+ else
+ {
+ if (keyword.startsWith("N: "))
+ keyword = keyword.replace("N: ", "");
+ else
+ {
+ changed = true;
+ playerAliases.put("N: " + key, replacement);
+ }
+ event.setMessage(event.getMessage().replace(keyword, replacement));
+ }
+ int maxLength;
+ try
+ {
+ maxLength = Integer.valueOf(getPermissionContent(player, "utils.alias.length."));
+ }
+ catch (NumberFormatException e)
+ {
+ maxLength = 255;
+ }
+ if (event.getMessage().length() > maxLength)
+ {
+ getLogger().message(player, true, "The generated message is too long!");
+ event.setCancelled(true);
+ return;
+ }
+ }
+ event.setMessage(ChatAPI.colorify(event.getPlayer(), event.getMessage()));
+ if (changed)
+ saveAliases(uuid);
+ }
+
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onPlayerCommand(PlayerCommandPreprocessEvent event)
+ {
+ if (event.isCancelled())
+ return;
+ boolean listening = false;
+ String command = "";
+ for (String s : commands)
+ {
+ command = "^\\/(.*:)?" + s + " ";
+ if (event.getMessage().matches(command + ".*"))
+ {
+ listening = true;
+ break;
+ }
+ }
+ if (!listening)
+ return;
+ Player player = event.getPlayer();
+ UUID uuid = player.getUniqueId();
+ JSONObject playerAliases = (JSONObject) aliases.get(uuid.toString());
+ String temp = event.getMessage().replaceAll(command, "");
+ command = event.getMessage().replaceAll(Pattern.quote(temp) + "$", "");
+ event.setMessage(event.getMessage().replaceFirst(Pattern.quote(command), ""));
+ for (Object key : playerAliases.keySet())
+ {
+ String keyword = (String) key;
+ String replacement = (String) playerAliases.get(key);
+ if (keyword.startsWith("R: "))
+ {
+ keyword = keyword.replace("R: ", "");
+ event.setMessage(event.getMessage().replaceAll(keyword, replacement));
+ }
+ else
+ {
+ if (keyword.startsWith("N: "))
+ keyword = keyword.replace("N: ", "");
+ event.setMessage(event.getMessage().replace(keyword, replacement));
+ }
+ int maxLength;
+ try
+ {
+ maxLength = Integer.valueOf(getPermissionContent(player, "utils.alias.length."));
+ }
+ catch (NumberFormatException e)
+ {
+ maxLength = 255;
+ }
+ if (event.getMessage().length() > maxLength)
+ {
+ getLogger().message(player, true, "The generated message is too long!");
+ event.setCancelled(true);
+ return;
+ }
+ }
+ event.setMessage(command + event.getMessage());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "addalias")
+ public boolean addAlias(CommandSender sender, boolean regex, String keyword, String replacement)
+ {
+ if (regex && keyword.equals(".*"))
+ {
+ getLogger().message(sender, true, "You may not define the wildcard regex as an alias.");
+ return true;
+ }
+ Player player = (Player) sender;
+ UUID uuid = player.getUniqueId();
+ JSONObject data = (JSONObject) aliases.get(uuid.toString());
+ keyword = (regex ? "R: " : "N: ") + keyword;
+ if (!data.containsKey(keyword))
+ {
+ int maxAmount;
+ try
+ {
+ maxAmount = Integer.valueOf(getPermissionContent(player, "utils.alias.amount."));
+ }
+ catch (NumberFormatException e)
+ {
+ maxAmount = 25;
+ }
+ if (data.size() == maxAmount)
+ {
+ getLogger().message(sender, true, "You already reached your maximum of aliases!");
+ return true;
+ }
+ }
+ data.put(keyword, replacement);
+ if (sender.hasPermission("essentials.chat.color"))
+ getLogger().message(sender,
+ "Successfully created alias " + keyword.substring(3) + " §7-> " + replacement + " §7for you.");
+ else
+ getLogger().message(sender,
+ "Successfully created alias " + keyword.substring(3) + " §7-> " + replacement + " §7for you.");
+ saveAliases(uuid);
+ return true;
+ }
+
+ @Command(hook = "delalias")
+ public boolean delAlias(CommandSender sender, boolean regex, String keyword)
+ {
+ Player player = (Player) sender;
+ UUID uuid = player.getUniqueId();
+ JSONObject data = (JSONObject) aliases.get(uuid.toString());
+ keyword = (regex ? "R: " : "N: ") + keyword;
+ if (data.remove(keyword) != null)
+ {
+ getLogger().message(sender, "Successfully removed the alias!");
+ saveAliases(uuid);
+ return true;
+ }
+ else
+ {
+ getLogger().message(sender, true, "That alias doesn't exist! Hint: regex/no regex does matter for this.");
+ return true;
+ }
+ }
+
+ @Command(hook = "listaliases")
+ public boolean listAliases(CommandSender sender)
+ {
+ ArrayList<String> message = new ArrayList<>();
+ Player player = (Player) sender;
+ UUID uuid = player.getUniqueId();
+ JSONObject data = (JSONObject) aliases.get(uuid.toString());
+ for (Object key : data.keySet())
+ message.add((String) key + " §7-> " + data.get(key));
+ getLogger().message(sender, message.toArray(new String[] {}));
+ return true;
+ }
+
+ private String getPermissionContent(Player player, String permnode)
+ {
+ Set<PermissionAttachmentInfo> perms = player.getEffectivePermissions();
+ for (PermissionAttachmentInfo perm : perms)
+ if (perm.getPermission().toString().startsWith(permnode))
+ return perm.getPermission().replace(permnode, "");
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void loadAliases(UUID uuid)
+ {
+ JSONObject defaults = new JSONObject();
+ defaults.put("dataFormat", "v1");
+ JSONObject data = new JSONObject();
+ data.put("N: ./", "/");
+ defaults.put("data", data);
+ JSONObject playerAliases = JsonManager
+ .getObject(new File(Main.plugin.getDataFolder(), "aliases/" + uuid.toString() + ".json"));
+ if (playerAliases == null)
+ {
+ playerAliases = defaults;
+ }
+ String dataFormat = (String) playerAliases.get("dataFormat");
+ if (dataFormat == null)
+ {
+ JSONObject temp = new JSONObject();
+ temp.put("dataFormat", "v1");
+ JSONObject tempAliases = new JSONObject();
+ {
+ for (Object key : playerAliases.keySet())
+ {
+ tempAliases.put("N: " + key, playerAliases.get(key));
+ }
+ }
+ temp.put("data", tempAliases);
+ aliases.put(uuid.toString(), temp.get("data"));
+ }
+ else if (dataFormat.equals("v1"))
+ aliases.put(uuid.toString(), playerAliases.get("data"));
+ else
+ {
+ getLogger().error("Unknown data format for alias set of player " + uuid.toString());
+ aliases.put(uuid.toString(), ((JSONObject) defaults.get("data")).clone());
+ saveAliases(uuid);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void saveAliases(UUID uuid)
+ {
+ JSONObject temp = new JSONObject();
+ temp.put("dataFormat", "v1");
+ temp.put("data", aliases.get(uuid.toString()));
+ JsonManager.save(temp, new File(Main.plugin.getDataFolder(), "aliases/" + uuid.toString() + ".json"));
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/chatgroups/Chatgroups.cmd b/src/main/java/com/redstoner/modules/chatgroups/Chatgroups.cmd
new file mode 100644
index 0000000..33fd0c5
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/chatgroups/Chatgroups.cmd
@@ -0,0 +1,35 @@
+command cgt {
+ [empty] {
+ help Toggles your cgtoggle status.;
+ type player;
+ run cgtoggle;
+ }
+}
+command cgkey {
+ [string:key] {
+ help Sets your chatgroup key.;
+ run setcgkey key;
+ type player;
+ }
+}
+command cgsay {
+ [string:message...] {
+ help Chats in your chatgroup.;
+ run cgsay message;
+ }
+}
+command cg {
+ join [string:group] {
+ help Joins a chatgroup.;
+ run cgjoin group;
+ }
+ leave {
+ help Leaves your chatgroup.;
+ run cgleave;
+ }
+ info {
+ help Displays info about your chatgroup.;
+ run cginfo;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/chatgroups/Chatgroups.java b/src/main/java/com/redstoner/modules/chatgroups/Chatgroups.java
new file mode 100644
index 0000000..457702c
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/chatgroups/Chatgroups.java
@@ -0,0 +1,400 @@
+package com.redstoner.modules.chatgroups;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.BroadcastFilter;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.ignore.Ignore;
+import com.redstoner.modules.socialspy.Socialspy;
+
+import net.nemez.chatapi.ChatAPI;
+
+/** The ChatGroups module. Allows people to have private sub-chats that can be accessed via a single char prefix or a toggle.
+ *
+ * @author Pepich */
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Chatgroups implements Module, Listener
+{
+ private static final char defaultKey = ':';
+ private static final File groupsLocation = new File(Main.plugin.getDataFolder(), "chatgroups.json");
+ private static final File keysLocation = new File(Main.plugin.getDataFolder(), "chatgroup_keys.json");
+ private ArrayList<UUID> cgtoggled;
+ private static JSONObject groups, keys;
+
+ @Override
+ public boolean onEnable()
+ {
+ groups = JsonManager.getObject(groupsLocation);
+ if (groups == null)
+ {
+ groups = new JSONObject();
+ saveGroups();
+ }
+ keys = JsonManager.getObject(keysLocation);
+ if (keys == null)
+ {
+ keys = new JSONObject();
+ saveKeys();
+ }
+ cgtoggled = new ArrayList<>();
+ return true;
+ }
+
+ @Override
+ public void onDisable()
+ {
+ saveKeys();
+ saveGroups();
+ }
+
+ /** Prints chatgroup info (like players in the group, groupname) to the sender.
+ *
+ * @param sender the issuer of the command.
+ * @return true. */
+ @SuppressWarnings("unchecked")
+ @Command(hook = "cginfo")
+ public boolean cgInfo(CommandSender sender)
+ {
+ String group = getGroup(sender);
+ if (group == null)
+ getLogger().message(sender, true, "You are not in a chatgroup!");
+ else
+ {
+ ArrayList<String> message = new ArrayList<>();
+ message.add("§7Your current chatgroup is: §6" + group);
+ ArrayList<String> players = new ArrayList<>();
+ Iterator<String> iter = groups.keySet().iterator();
+ while (iter.hasNext())
+ {
+ String id = iter.next();
+ if (((String) groups.get(id)).equals(group))
+ {
+ if (!id.equals("CONSOLE"))
+ {
+ UUID uuid = UUID.fromString(id);
+ Player p = Bukkit.getPlayer(uuid);
+ if (p != null)
+ players.add(p.getDisplayName());
+ else
+ players.add(Bukkit.getOfflinePlayer(UUID.fromString(id)).getName());
+ }
+ else
+ players.add(id);
+ }
+ }
+ StringBuilder sb = new StringBuilder("&6Other players in this group: &9");
+ for (String player : players)
+ {
+ sb.append(player);
+ sb.append("&7, &9");
+ }
+ sb.delete(sb.length() - 2, sb.length());
+ message.add(sb.toString());
+ getLogger().message(sender, message.toArray(new String[] {}));
+ }
+ return true;
+ }
+
+ /** Prints a Players cgkey to their chat.
+ *
+ * @param sender the issuer of the command. */
+ public void getCgKey(CommandSender sender)
+ {
+ getLogger().message(sender, "Your current cgkey is §6" + getKey((Player) sender));
+ }
+
+ /** Sets the cgkey of a Player.
+ *
+ * @param sender the issuer of the command.
+ * @param key the key to be set. Set to NULL or "" to get your current key.
+ * @return true. */
+ @SuppressWarnings("unchecked")
+ @Command(hook = "setcgkey")
+ public boolean setCgKey(CommandSender sender, String key)
+ {
+ if (key.length() > 1)
+ {
+ getLogger().message(sender, true,
+ "Could not set your key to §6" + key + " §7, it can be at most one char.");
+ return true;
+ }
+ if (key == null || key.length() == 0)
+ {
+ getCgKey(sender);
+ return true;
+ }
+ getLogger().message(sender, "Set your key to §6" + key);
+ keys.put(((Player) sender).getUniqueId().toString(), key + "");
+ saveKeys();
+ return true;
+ }
+
+ /** Let's a Player toggle their auto-cg status to allow for automatically sending chat messages to their chatgroup.
+ *
+ * @param sender the issuer of the command.
+ * @return true. */
+ @Command(hook = "cgtoggle")
+ public boolean cgToggleCommand(CommandSender sender)
+ {
+ if (getGroup(sender) != null)
+ if (cgtoggled.contains(((Player) sender).getUniqueId()))
+ {
+ cgtoggled.remove(((Player) sender).getUniqueId());
+ getLogger().message(sender, "CGT now §cdisabled");
+ }
+ else
+ {
+ cgtoggled.add(((Player) sender).getUniqueId());
+ getLogger().message(sender, "CGT now §aenabled");
+ }
+ else
+ getLogger().message(sender, true, "You are not in a chatgroup!");
+ return true;
+ }
+
+ /** Lets a CommandSender leave their group.
+ *
+ * @param sender the command issuer.
+ * @return true. */
+ @Command(hook = "cgleave")
+ public boolean cgLeave(CommandSender sender)
+ {
+ String group = removeGroup(sender);
+ if (group == null)
+ {
+ getLogger().message(sender, true, "You were not in a chatgroup!");
+ return true;
+ }
+ String name = Utils.getName(sender);
+ sendToGroup(group, "&9" + name + " &7left the group!");
+ getLogger().message(sender, "Successfully removed you from your group!");
+ if (sender instanceof Player)
+ cgtoggled.remove(((Player) sender).getUniqueId());
+ return true;
+ }
+
+ /** Lets a CommandSender join a group.
+ *
+ * @param sender the command issuer.
+ * @param name the name of the group.
+ * @return true. */
+ @Command(hook = "cgjoin")
+ public boolean cgJoin(CommandSender sender, String name)
+ {
+ String pname = Utils.getName(sender);
+ String group = getGroup(sender);
+ if (group != null && group.equals(name))
+ getLogger().message(sender, true, "You were already in group §6" + name);
+ else
+ {
+ setGroup(sender, null);
+ if (group != null)
+ sendToGroup(group, "&9" + pname + " &7left the group!");
+ sendToGroup(name, "&9" + pname + " &7joined the group!");
+ setGroup(sender, name);
+ getLogger().message(sender, "Successfully joined group §6" + name);
+ }
+ return true;
+ }
+
+ /** Sends a message to a group.
+ *
+ * @param sender the sender of the message - the message will be sent to the group of the sender.
+ * @param message the message to be sent.
+ * @return true. */
+ @Command(hook = "cgsay")
+ public boolean cgSay(CommandSender sender, String message)
+ {
+ String group = getGroup(sender);
+ if (group != null)
+ sendToGroup(sender, message);
+ else
+ getLogger().message(sender, true, "You are not in a chatgroup right now!");
+ return true;
+ }
+
+ /** Deals with chat events to allow for cgkeys and cgtoggle.
+ *
+ * @param event the chat event containing the player and the message. */
+ @EventHandler
+ public void onPlayerChat(AsyncPlayerChatEvent event)
+ {
+ String group = getGroup(event.getPlayer());
+ Player player = event.getPlayer();
+ if (group != null)
+ {
+ if (event.getMessage().startsWith(getKey(player)))
+ {
+ event.setCancelled(true);
+ sendToGroup(event.getPlayer(), event.getMessage().substring(1));
+ }
+ else if (cgtoggled.contains(event.getPlayer().getUniqueId()))
+ {
+ event.setCancelled(true);
+ sendToGroup(event.getPlayer(), event.getMessage());
+ }
+ }
+ }
+
+ /** Finds the group of a CommandSender.
+ *
+ * @param target the CommandSender to get the group of.
+ * @return the group of the target or NULL if he doesn't have one. */
+ public static String getGroup(CommandSender target)
+ {
+ if (target instanceof Player)
+ return (String) groups.get(((Player) target).getUniqueId().toString());
+ else
+ return (String) groups.get("CONSOLE");
+ }
+
+ /** Sets the group of the CommandSender.
+ *
+ * @param target the CommandSender to set the group of.
+ * @param group the name of the group to join. */
+ @SuppressWarnings("unchecked")
+ private void setGroup(CommandSender target, String group)
+ {
+ if (target instanceof Player)
+ groups.put(((Player) target).getUniqueId().toString(), group);
+ else
+ groups.put("CONSOLE", group);
+ saveGroups();
+ }
+
+ /** Removes a CommandSender from their chatgroup. Will also save the groups after finishing
+ *
+ * @param target the CommandSender to get their group removed. */
+ private String removeGroup(CommandSender target)
+ {
+ String group;
+ if (target instanceof Player)
+ group = (String) groups.remove(((Player) target).getUniqueId().toString());
+ else
+ group = (String) groups.remove("CONSOLE");
+ saveGroups();
+ return group;
+ }
+
+ /** This method will find the ChatgGroup key of any player.
+ *
+ * @param player the player to get the key from.
+ * @return the key. */
+ public static String getKey(Player player)
+ {
+ String key = (String) keys.get(player.getUniqueId().toString());
+ return (key == null ? "" + defaultKey : key);
+ }
+
+ /** This method sends a message to a chatgroup.
+ *
+ * @param sender the sender of the message. Also defines which group the message will be sent to.
+ * @param message the message to be sent. */
+ private void sendToGroup(CommandSender sender, String message)
+ {
+ String name = Utils.getName(sender);
+ String group = getGroup(sender);
+ message = ChatAPI.colorify(null, message);
+
+ BroadcastFilter ignore = ModuleLoader.exists("Ignore")? Ignore.getIgnoredBy(sender) : null;
+ Utils.broadcast("§8[§bCG§8] §9", name + "§8: §6" + message, new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+
+ String rgroup = getGroup(recipient);
+ if ( rgroup != null && (ignore == null? true : ignore.sendTo(recipient)) )
+ return rgroup.equals(group);
+ else
+ return false;
+ }
+ });
+ if (ModuleLoader.getModule("Socialspy") != null)
+ {
+ Socialspy.spyBroadcast(sender, "§e" + group + " §a(cg)", message, "/cg", new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return getGroup(recipient) == null || !getGroup(recipient).equals(group);
+ }
+ });
+ }
+ if (getGroup(Bukkit.getConsoleSender()) == null || !getGroup(Bukkit.getConsoleSender()).equals(group))
+ {
+ getLogger().info(name + " in " + group + ": " + message + " §8(hidden)");
+ }
+ }
+
+ /** This method sends a message to a chatgroup.
+ *
+ * @param sender the sender of the message. Also defines which group the message will be sent to.
+ * @param message the message to be sent. */
+ private void sendToGroup(String group, String message)
+ {
+ message = ChatAPI.colorify(null, message);
+ Utils.broadcast(null, message, new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ String rgroup = getGroup(recipient);
+ if (rgroup != null)
+ return rgroup.equals(group);
+ else
+ return false;
+ }
+ });
+ if (ModuleLoader.getModule("Socialspy") != null)
+ {
+ Socialspy.spyBroadcast(Bukkit.getConsoleSender(), "§e" + group + " §a(cg)", message, "/cg",
+ new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return getGroup(recipient) == null || !getGroup(recipient).equals(group);
+ }
+ });
+ }
+ if (getGroup(Bukkit.getConsoleSender()) == null || !getGroup(Bukkit.getConsoleSender()).equals(group))
+ {
+ getLogger().info("In " + group + ": " + message + " §8(hidden)");
+ }
+ }
+
+ /** Saves the groups. */
+ private void saveGroups()
+ {
+ JsonManager.save(groups, groupsLocation);
+ }
+
+ /** Saves the keys. */
+ private void saveKeys()
+ {
+ JsonManager.save(keys, keysLocation);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/check/Check.cmd b/src/main/java/com/redstoner/modules/check/Check.cmd
new file mode 100644
index 0000000..87cadbd
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/check/Check.cmd
@@ -0,0 +1,8 @@
+command check {
+ perm utils.check;
+
+ [string:player] {
+ run checkCommand player;
+ help Get info on a player;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/check/Check.java b/src/main/java/com/redstoner/modules/check/Check.java
new file mode 100644
index 0000000..48bf579
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/check/Check.java
@@ -0,0 +1,247 @@
+package com.redstoner.modules.check;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Scanner;
+
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.command.CommandSender;
+import org.bukkit.event.Listener;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.Command.AsyncType;
+import com.nemez.cmdmgr.CommandManager;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.mysql.JSONManager;
+import com.redstoner.misc.mysql.MysqlHandler;
+import com.redstoner.misc.mysql.elements.ConstraintOperator;
+import com.redstoner.misc.mysql.elements.MysqlConstraint;
+import com.redstoner.misc.mysql.elements.MysqlDatabase;
+import com.redstoner.misc.mysql.elements.MysqlTable;
+import com.redstoner.modules.Module;
+
+import net.nemez.chatapi.click.Message;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Check implements Module, Listener
+{
+ MysqlTable table;
+
+ @Override
+ public boolean onEnable()
+ {
+ Map<Serializable, Serializable> config = JSONManager.getConfiguration("check.json");
+ if (config == null || !config.containsKey("database") || !config.containsKey("table"))
+ {
+ getLogger().error("Could not load the Check config file, disabling!");
+ return false;
+ }
+ try
+ {
+ MysqlDatabase database = MysqlHandler.INSTANCE
+ .getDatabase((String) config.get("database") + "?autoReconnect=true");
+ table = database.getTable((String) config.get("table"));
+ }
+ catch (NullPointerException e)
+ {
+ getLogger().error("Could not use the Check config, disabling!");
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void postEnable()
+ {
+ CommandManager.registerCommand(getCommandString(), this, Main.plugin);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Command(hook = "checkCommand", async = AsyncType.ALWAYS)
+ public void checkCommand(final CommandSender sender, final String player)
+ {
+ getLogger().message(sender, "&7Please note that the data may not be fully accurate!");
+ OfflinePlayer oPlayer;
+ oPlayer = Bukkit.getPlayer(player);
+ if (oPlayer == null)
+ oPlayer = Bukkit.getServer().getOfflinePlayer(player);
+ sendData(sender, oPlayer);
+ if (ModuleLoader.exists("Tag"))
+ Bukkit.dispatchCommand(sender, "tag check " + player);
+ }
+
+ public String read(URL url)
+ {
+ String data = "";
+ try
+ {
+ Scanner in = new Scanner(new InputStreamReader(url.openStream()));
+ while (in.hasNextLine())
+ {
+ data += in.nextLine();
+ }
+ in.close();
+ return data;
+ }
+ catch (IOException e)
+ {}
+ return null;
+ }
+
+ public JSONObject getIpInfo(OfflinePlayer player)
+ {
+ String ip = "";
+ if (player.isOnline())
+ {
+ ip = player.getPlayer().getAddress().getHostString();
+ }
+ else
+ {
+ try
+ {
+ ip = (String) table.get("last_ip", new MysqlConstraint("uuid", ConstraintOperator.EQUAL,
+ player.getUniqueId().toString().replace("-", "")))[0];
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+ try
+ {
+ URL ipinfo = new URL("https://ipinfo.io/" + ip + "/json");
+ String rawJson = read(ipinfo);
+ return (JSONObject) new JSONParser().parse(rawJson);
+ }
+ catch (Exception e)
+ {}
+ return null;
+ }
+
+ public String getFirstJoin(OfflinePlayer player)
+ {
+ Long firstJoin = player.getFirstPlayed();
+ Date date = new Date(firstJoin);
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+ return format.format(date);
+ }
+
+ public String getLastSeen(OfflinePlayer player)
+ {
+ Long lastSeen = player.getLastPlayed();
+ Date date = new Date(lastSeen);
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+ return format.format(date);
+ }
+
+ public Object[] getWebsiteData(OfflinePlayer player)
+ {
+ MysqlConstraint constraint = new MysqlConstraint("uuid", ConstraintOperator.EQUAL,
+ player.getUniqueId().toString().replace("-", ""));
+ try
+ {
+ int id = (int) table.get("id", constraint)[0];
+ String email = (String) table.get("email", constraint)[0];
+ boolean confirmed = (boolean) table.get("confirmed", constraint)[0];
+ return new Object[] {"https://redstoner.com/users/" + id, email, confirmed};
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ int id = (int) table.get("id", constraint)[0];
+ String email = (String) table.get("email", constraint)[0];
+ boolean confirmed = (boolean) table.get("confirmed", constraint)[0];
+ return new Object[] {"https://redstoner.com/users/" + id, email, confirmed};
+ }
+ catch (Exception e2)
+ {}
+ return new Object[] {null};
+ }
+ }
+
+ public String getCountry(JSONObject data)
+ {
+ return (String) data.get("country");
+ }
+
+ public String getAllNames(OfflinePlayer player)
+ {
+ String uuid = player.getUniqueId().toString().replace("-", "");
+ String nameString = "";
+ try
+ {
+ String rawJson = read(new URL("https://api.mojang.com/user/profiles/" + uuid + "/names"));
+ JSONArray names = (JSONArray) new JSONParser().parse(rawJson);
+ for (Object obj : names)
+ {
+ nameString += "&e" + ((JSONObject) obj).get("name") + "&7, ";
+ }
+ nameString = nameString.substring(0, nameString.length() - 2);
+ return nameString;
+ }
+ catch (Exception e)
+ {}
+ return null;
+ }
+
+ public void sendData(CommandSender sender, OfflinePlayer player)
+ {
+ try
+ {
+ JSONObject ipInfo = getIpInfo(player);
+ // data
+ String firstJoin = getFirstJoin(player);
+ String lastSeen = getLastSeen(player);
+ firstJoin = (firstJoin.equals("1970-01-01 01:00")) ? "&eNever" : "&7(yyyy-MM-dd hh:mm) &e" + firstJoin;
+ lastSeen = (lastSeen.equals("1970-1-1 01:00")) ? "&eNever" : "&7(yyyy-MM-dd hh:mm) &e" + lastSeen;
+ Object[] websiteData = getWebsiteData(player);
+ String websiteUrl = (websiteData[0] == null) ? "None" : (String) websiteData[0];
+ String email = (websiteData[0] == null) ? "Unknown" : (String) websiteData[1];
+ boolean emailNotConfirmed = (websiteData[0] == null) ? false : !((boolean) websiteData[2]);
+ String country = (ipInfo == null) ? "Unknown" : getCountry(ipInfo);
+ String namesUsed = getAllNames(player);
+ if (namesUsed == null)
+ namesUsed = "None";
+ // messages
+ List<Message> messages = new ArrayList<>();
+ messages.add(new Message(sender, null).appendText(getLogger().getHeader()));
+ messages.add(new Message(sender, null).appendText("&7Data provided by redstoner:"));
+ messages.add(new Message(sender, null).appendSuggestHover("&6> UUID: &e" + player.getUniqueId().toString(),
+ player.getUniqueId().toString(), "Click to copy into chatbox!"));
+ messages.add(new Message(sender, null).appendText("&6> First joined: &e" + firstJoin));
+ messages.add(new Message(sender, null).appendText("&6> Last seen: &e" + lastSeen));
+ messages.add(
+ new Message(sender, null).appendText("&6> Website account: &e").appendLink(websiteUrl, websiteUrl));
+ messages.add(new Message(sender, null).appendText("&6> Email: &e")
+ .appendText((emailNotConfirmed ? "&6> &4Email NOT Confirmed!&e" : "&e") + email));
+ messages.add(new Message(sender, null).appendText("&7Data provided by ipinfo:"));
+ messages.add(new Message(sender, null).appendText("&6> Country: &e" + country));
+ messages.add(new Message(sender, null).appendText("&7Data provided by mojang:"));
+ messages.add(new Message(sender, null).appendText("&6> All ingame names used so far: &e" + namesUsed));
+ for (Message m : messages)
+ m.send();
+ }
+ catch (Exception e)
+ {
+ getLogger().message(sender, true, "Sorry, something went wrong while fetching data");
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/clear/Clear.cmd b/src/main/java/com/redstoner/modules/clear/Clear.cmd
new file mode 100644
index 0000000..117804b
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/clear/Clear.cmd
@@ -0,0 +1,13 @@
+command clear{
+ [empty] {
+ help Clears your inventory;
+ type player;
+ perm utils.clear;
+ run clear;
+ }
+ [string:player] {
+ help Clears someone elses inventory;
+ perm utils.admin.clear;
+ run clearother player;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/clear/Clear.java b/src/main/java/com/redstoner/modules/clear/Clear.java
new file mode 100644
index 0000000..a6ea86f
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/clear/Clear.java
@@ -0,0 +1,44 @@
+package com.redstoner.modules.clear;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Clear implements Module
+{
+ @Command(hook = "clear")
+ public boolean clearInventory(CommandSender sender)
+ {
+ Player player = (Player) sender;
+ Inventory inv = player.getInventory();
+ for (int i = 0; i < 36; i++)
+ inv.clear(i);
+ getLogger().message(sender, "Cleared your inventory!");
+ return true;
+ }
+
+ @Command(hook = "clearother")
+ public boolean clearOtherInventory(CommandSender sender, String name)
+ {
+ Player player = Bukkit.getPlayer(name);
+ if (player == null)
+ getLogger().message(sender, true, "That player couldn't be found!");
+ else
+ {
+ Inventory inv = player.getInventory();
+ for (int i = 0; i < 36; i++)
+ inv.clear(i);
+ getLogger().message(sender, "Cleared " + player.getDisplayName() + "&7's inventory!");
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/cycle/Cycle.cmd b/src/main/java/com/redstoner/modules/cycle/Cycle.cmd
new file mode 100644
index 0000000..dc8e10a
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/cycle/Cycle.cmd
@@ -0,0 +1,12 @@
+command cycle {
+ on {
+ help Turns on cycle;
+ type player;
+ run cycle_on;
+ }
+ off {
+ help Turns off cycle;
+ type player;
+ run cycle_off;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/cycle/Cycle.java b/src/main/java/com/redstoner/modules/cycle/Cycle.java
new file mode 100644
index 0000000..b0a6310
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/cycle/Cycle.java
@@ -0,0 +1,142 @@
+package com.redstoner.modules.cycle;
+
+import java.io.File;
+import java.util.UUID;
+
+import org.bukkit.GameMode;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerItemHeldEvent;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.json.simple.JSONArray;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Cycle implements Module, Listener
+{
+ private File cycleFile = new File(Main.plugin.getDataFolder(), "cycle.json");
+ private JSONArray no_cyclers;
+
+ @Override
+ public boolean onEnable()
+ {
+ no_cyclers = JsonManager.getArray(cycleFile);
+ if (no_cyclers == null)
+ no_cyclers = new JSONArray();
+ return true;
+ }
+
+ @Override
+ public void onDisable()
+ {
+ saveCyclers();
+ }
+
+ private void saveCyclers()
+ {
+ JsonManager.save(no_cyclers, cycleFile);
+ }
+
+ @Command(hook = "cycle_on")
+ public boolean cycleOn(CommandSender sender)
+ {
+ UUID uid = ((Player) sender).getUniqueId();
+ if (no_cyclers.remove(uid.toString()))
+ {
+ getLogger().message(sender, "Cycle enabled!");
+ saveCyclers();
+ }
+ else
+ getLogger().message(sender, "Cycle was already enabled!");
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "cycle_off")
+ public boolean cycleOff(CommandSender sender)
+ {
+ UUID uid = ((Player) sender).getUniqueId();
+ if (!no_cyclers.contains(uid.toString()))
+ {
+ getLogger().message(sender, "Cycle disabled!");
+ no_cyclers.add(uid.toString());
+ saveCyclers();
+ }
+ else
+ getLogger().message(sender, "Cycle was already disabled!");
+ return true;
+ }
+
+ @EventHandler
+ public void onInventoryCycle(PlayerItemHeldEvent event)
+ {
+ Player player = event.getPlayer();
+ UUID uid = player.getUniqueId();
+ if (!player.getGameMode().equals(GameMode.CREATIVE) || player.isSneaking()
+ || no_cyclers.contains(uid.toString()))
+ return;
+ int prev_slot = event.getPreviousSlot();
+ int new_slot = event.getNewSlot();
+ if (prev_slot == 0 && new_slot == 8)
+ shift(player, false);
+ else if (prev_slot == 8 && new_slot == 0)
+ shift(player, true);
+ }
+
+ private void shift(Player player, boolean down)
+ {
+ Inventory inv = player.getInventory();
+ ItemStack[] items = inv.getStorageContents();
+ int shift = down ? -9 : 9;
+ shift = (shift + items.length) % items.length;
+ for (int i = 0; i < 4; i++)
+ {
+ items = join(subset(items, shift, items.length), subset(items, 0, shift));
+ ItemStack[] hotbar = subset(items, 0, 9);
+ boolean found = false;
+ for (ItemStack item : hotbar)
+ if (item != null)
+ {
+ found = true;
+ break;
+ }
+ if (found)
+ break;
+ }
+ inv.setStorageContents(items);
+ }
+
+ private ItemStack[] subset(ItemStack[] items, int start, int end)
+ {
+ ItemStack[] result = new ItemStack[end - start];
+ for (int i = start; i < end; i++)
+ {
+ result[i - start] = items[i];
+ }
+ return result;
+ }
+
+ private ItemStack[] join(ItemStack[] items1, ItemStack[] items2)
+ {
+ ItemStack[] result = new ItemStack[items1.length + items2.length];
+ for (int i = 0; i < items1.length; i++)
+ result[i] = items1[i];
+ int offset = items1.length;
+ for (int i = 0; i < items2.length; i++)
+ result[i + offset] = items2[i];
+ return result;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/damnspam/DamnSpam.cmd b/src/main/java/com/redstoner/modules/damnspam/DamnSpam.cmd
new file mode 100644
index 0000000..404968e
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/damnspam/DamnSpam.cmd
@@ -0,0 +1,15 @@
+command damnspam {
+ perm utils.damnspam;
+
+ [double:seconds] {
+ run damnspamSingle seconds;
+ help Set single input cooldown for button or lever.;
+ type player;
+ }
+
+ [double:secondsOff] [double:secondsOn] {
+ run damnspamDouble secondsOff secondsOn;
+ help Set input cooldown after it's been turned off and turned on (for lever only).;
+ type player;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/damnspam/DamnSpam.java b/src/main/java/com/redstoner/modules/damnspam/DamnSpam.java
new file mode 100644
index 0000000..fa5af87
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/damnspam/DamnSpam.java
@@ -0,0 +1,350 @@
+package com.redstoner.modules.damnspam;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+
+import net.nemez.chatapi.ChatAPI;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 1, compatible = 4)
+public class DamnSpam implements Module, Listener
+{
+ File configFile = new File(Main.plugin.getDataFolder(), "DamnSpam.json");
+ Map<String, SpamInput> inputs;
+ boolean changingInput = false;
+ List<Material> acceptedInputs;
+ HashMap<Material, int[][]> attachedBlocks;
+ HashMap<Player, SpamInput> players;
+ int maxTimeout = 240;
+ String timeoutErrorString = "The timeout must be -1 or within 0 and " + maxTimeout;
+
+ @Override
+ public boolean onEnable()
+ {
+ loadInputs();
+ acceptedInputs = new ArrayList<Material>();
+ Collections.addAll(acceptedInputs, Material.WOOD_BUTTON, Material.STONE_BUTTON, Material.LEVER);
+ attachedBlocks = new HashMap<Material, int[][]>();
+ attachedBlocks.put(Material.LEVER,
+ new int[][] {{0, 7, 8, 15}, {5, 6, 13, 14}, {4, 12}, {3, 11}, {2, 10}, {1, 9}});
+ attachedBlocks.put(Material.STONE_BUTTON,
+ new int[][] {{0, 8}, {5, 6, 7, 13, 14, 15}, {4, 12}, {3, 11}, {2, 10}, {1, 9}});
+ attachedBlocks.put(Material.WOOD_BUTTON,
+ new int[][] {{0, 8}, {5, 6, 7, 13, 14, 15}, {4, 12}, {3, 11}, {2, 10}, {1, 9}});
+ players = new HashMap<Player, SpamInput>();
+ return true;
+ }
+
+ public void loadInputs()
+ {
+ inputs = new HashMap<String, SpamInput>();
+ try
+ {
+ FileReader reader = new FileReader(configFile);
+ JSONObject json = (JSONObject) new JSONParser().parse(reader);
+ for (Object key : json.keySet())
+ {
+ JSONObject inputData = (JSONObject) json.get(key);
+ String uuid = (String) inputData.get("creator");
+ Double timeoutOn = (Double) inputData.get("timeout_on");
+ Double timeoutOff = (Double) inputData.get("timeout_off");
+ Double lastTime = (Double) inputData.get("last_time");
+ inputs.put((String) key, new SpamInput(uuid, timeoutOff, timeoutOn, lastTime));
+ }
+ }
+ catch (IOException | ParseException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void saveInputs()
+ {
+ JSONObject json = new JSONObject();
+ for (String key : inputs.keySet())
+ {
+ JSONObject jsonInput = new JSONObject();
+ SpamInput input = inputs.get(key);
+ jsonInput.put("creator", input.player);
+ jsonInput.put("timeout_on", input.timeoutOn);
+ jsonInput.put("timeout_off", input.timeoutOff);
+ jsonInput.put("last_time", input.lastTime);
+ json.put(key, jsonInput);
+ }
+ try
+ {
+ PrintWriter writer = new PrintWriter(configFile);
+ writer.write(json.toJSONString());
+ writer.close();
+ }
+ catch (FileNotFoundException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public String locationString(Location loc)
+ {
+ return loc.getWorld().getName() + ";" + loc.getBlockX() + ";" + loc.getBlockY() + ";" + loc.getBlockZ();
+ }
+
+ public boolean isAcceptableTimeout(double timeout)
+ {
+ return (timeout > 0 && timeout <= maxTimeout) || timeout == -1;
+ }
+
+ public boolean canBuild(Player player, Block block)
+ {
+ BlockBreakEvent event = new BlockBreakEvent(block, player);
+ Bukkit.getPluginManager().callEvent(event);
+ return !event.isCancelled();
+ }
+
+ @Command(hook = "damnspamSingle")
+ public void damnspam(CommandSender sender, double seconds)
+ {
+ boolean destroyingInput = false;
+ seconds = (double) Math.round(seconds * 100) / 100;
+ if (seconds == 0)
+ destroyingInput = true;
+ else if (!isAcceptableTimeout(seconds))
+ {
+ ChatAPI.sendActionBar(sender, "&cThe timeout must be &e-1&c or within &e0&c and &e" + maxTimeout);
+ return;
+ }
+ ChatAPI.sendActionBar(sender, "&7Please click the input you would like to set.");
+ setPlayer((Player) sender, destroyingInput, seconds, seconds);
+ }
+
+ @Command(hook = "damnspamDouble")
+ public void damnspam(CommandSender sender, double secondsOff, double secondsOn)
+ {
+ boolean destroyingInput = false;
+ secondsOn = (double) Math.round(secondsOn * 100) / 100;
+ secondsOff = (double) Math.round(secondsOff * 100) / 100;
+ if (secondsOn == 0 && secondsOff == 0)
+ {
+ destroyingInput = true;
+ }
+ else if (!(isAcceptableTimeout(secondsOn) && isAcceptableTimeout(secondsOff)))
+ {
+ ChatAPI.sendActionBar(sender, "&cThe timeout must be &e-1&c or within &e0&c and &e" + maxTimeout);
+ return;
+ }
+ ChatAPI.sendActionBar(sender, "Please click the input you would like to set.");
+ setPlayer((Player) sender, destroyingInput, secondsOff, secondsOn);
+ }
+
+ public void setPlayer(Player player, boolean destroying, double timeoutOff, double timeoutOn)
+ {
+ SpamInput input = null;
+ if (!destroying)
+ {
+ input = new SpamInput(player.getUniqueId().toString(), timeoutOff, timeoutOn, 0);
+ }
+ players.put(player, input);
+ }
+
+ public boolean attemptInputRegister(Player player, Block block, Cancellable event)
+ {
+ if (players.containsKey(player))
+ {
+ if (!acceptedInputs.contains(block.getType()))
+ {
+ ChatAPI.sendActionBar(player, "&cThat block is not an acceptable input!");
+ return true;
+ }
+ String typeStr = block.getType().toString().toLowerCase().replace("_", " ");
+ String locationStr = locationString(block.getLocation());
+ changingInput = true;
+ boolean buildCheck = canBuild(player, block);
+ changingInput = false;
+ if (!buildCheck)
+ {
+ ChatAPI.sendActionBar(player,
+ "&cSomething went wrong trying to change the timeout of the " + typeStr + "!");
+ event.setCancelled(true);
+ return true;
+ }
+ SpamInput input = players.get(player);
+ if (input == null)
+ {
+ if (!inputs.containsKey(locationStr))
+ {
+ ChatAPI.sendActionBar(player,
+ "&cSomething went wrong trying to change the timeout of the" + typeStr + "!");
+ event.setCancelled(true);
+ return true;
+ }
+ inputs.remove(locationStr);
+ ChatAPI.sendActionBar(player, "&7Successfully removed the timeout for the " + typeStr);
+ }
+ else
+ {
+ inputs.put(locationStr, players.get(player));
+ ChatAPI.sendActionBar(player, "&7Successfully removed the timeout for the " + typeStr);
+ }
+ event.setCancelled(true);
+ players.remove(player);
+ saveInputs();
+ return true;
+ }
+ return false;
+ }
+
+ public void checkBlockBreak(BlockBreakEvent event, Block block)
+ {
+ if (!acceptedInputs.contains(block.getType()))
+ return;
+ String posStr = locationString(block.getLocation());
+ if (!inputs.containsKey(posStr))
+ return;
+ SpamInput input = inputs.get(posStr);
+ Player sender = event.getPlayer();
+ String typeStr = block.getType().toString().toLowerCase().replace("_", " ");
+ String inputStr = (block.getLocation().equals(event.getBlock()) ? "this " + typeStr
+ : "the " + typeStr + " attached to that block");
+ if (!sender.isSneaking())
+ {
+ ChatAPI.sendActionBar(sender, "&7To destroy " + inputStr + ", hold &esneak&7 while breaking it.");
+ event.setCancelled(true);
+ return;
+ }
+ if (sender.hasPermission("damnspam.admin") || sender.getUniqueId().toString().equals(input.player))
+ {
+ inputs.remove(posStr);
+ saveInputs();
+ ChatAPI.sendActionBar(sender, "&7Succesfully destroyed the" + typeStr + ".");
+ }
+ else
+ {
+ ChatAPI.sendActionBar(sender, "You are not allowed to remove " + inputStr);
+ event.setCancelled(true);
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public List<Block> getAttachedBlocks(Block block)
+ {
+ List<Block> blocks = new ArrayList<Block>();
+ BlockFace[] directions = {BlockFace.DOWN, BlockFace.UP, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST,
+ BlockFace.EAST};
+ for (int i = 0; i < directions.length; i++)
+ {
+ Block side = block.getRelative(directions[i]);
+ int[][] dvalues = attachedBlocks.get(side.getType());
+ if (dvalues != null)
+ {
+ boolean onSide = false;
+ for (int val : dvalues[i])
+ {
+ if (side.getData() == (byte) val)
+ {
+ onSide = true;
+ break;
+ }
+ }
+ if (onSide)
+ blocks.add(side);
+ }
+ }
+ return blocks;
+ }
+
+ @EventHandler(priority = EventPriority.NORMAL)
+ public void onBreak(BlockBreakEvent event)
+ {
+ if (changingInput || event.isCancelled())
+ return;
+ boolean register = attemptInputRegister(event.getPlayer(), event.getBlock(), event);
+ if (!register)
+ {
+ Block block = event.getBlock();
+ checkBlockBreak(event, block);
+ for (Block affected : getAttachedBlocks(block))
+ {
+ checkBlockBreak(event, affected);
+ }
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onInteract(PlayerInteractEvent event)
+ {
+ if (event.getClickedBlock() == null)
+ return;
+ boolean register = attemptInputRegister(event.getPlayer(), event.getClickedBlock(), event);
+ if (!register && event.getAction().equals(Action.RIGHT_CLICK_BLOCK) && !event.isCancelled())
+ {
+ Player sender = event.getPlayer();
+ Block block = event.getClickedBlock();
+ String posStr = locationString(block.getLocation());
+ SpamInput data = inputs.get(posStr);
+ if (data != null)
+ {
+ String btype = block.getType().toString().toLowerCase().replace("_", " ");
+ double checktime = 0;
+ if (btype.equals("lever") && block.getData() < 8)
+ checktime = data.timeoutOff;
+ else
+ checktime = data.timeoutOn;
+ double timeLeft = (data.lastTime + checktime)
+ - ((double) Math.round((double) System.currentTimeMillis() / 10) / 100);
+ timeLeft = (double) Math.round(timeLeft * 100) / 100;
+ if (checktime == -1)
+ {
+ event.setCancelled(true);
+ ChatAPI.sendActionBar(sender, "&7This " + btype + " is locked permanently by /damnspam.");
+ }
+ else if (timeLeft > 0)
+ {
+ event.setCancelled(true);
+ ChatAPI.sendActionBar(sender, "&7This " + btype + " has a damnspam timeout of &e" + checktime + "&7, with &e"
+ + timeLeft + "&7 left.");
+ }
+ else
+ {
+ data.lastTime = (double) Math.round((double) System.currentTimeMillis() / 10) / 100;
+ }
+ inputs.put(posStr, data);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/damnspam/SpamInput.java b/src/main/java/com/redstoner/modules/damnspam/SpamInput.java
new file mode 100644
index 0000000..9735dd9
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/damnspam/SpamInput.java
@@ -0,0 +1,17 @@
+package com.redstoner.modules.damnspam;
+
+public class SpamInput {
+
+ protected String player;
+ protected double timeoutOn;
+ protected double timeoutOff;
+ protected double lastTime;
+
+ protected SpamInput(String player, double timeoutOff, double timeoutOn, double lastTime) {
+ this.player = player;
+ this.timeoutOff = timeoutOff;
+ this.timeoutOn = timeoutOn;
+ this.lastTime = lastTime;
+ }
+
+}
diff --git a/src/main/java/com/redstoner/modules/datamanager/DataManager.cmd b/src/main/java/com/redstoner/modules/datamanager/DataManager.cmd
new file mode 100644
index 0000000..f7d480a
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/datamanager/DataManager.cmd
@@ -0,0 +1,34 @@
+command data {
+ import [string:file] as [string:module] {
+ run import_file file module;
+ type console;
+ }
+}
+
+command config {
+ alias configs;
+ alias setting;
+ alias settings;
+ perm datamanager.admin;
+ list {
+ run config_list;
+ help Lists all modules that have at least one config setting.;
+ }
+ list [string:module] {
+ run config_list2 module;
+ help Lists all config settings of the specified module.;
+ }
+ get [string:module] [string:key] {
+ run config_get module key;
+ help Displays the value of the specified setting.;
+ }
+ set [string:module] [string:key] [string:value...] {
+ run config_set module key value;
+ help Assigns a new value to the given setting.;
+ }
+ remove_all [string:module] {
+ run config_remove_all module;
+ type console;
+ help Deletes all config settings of a given module.;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/datamanager/DataManager.java b/src/main/java/com/redstoner/modules/datamanager/DataManager.java
new file mode 100644
index 0000000..63ce1ce
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/datamanager/DataManager.java
@@ -0,0 +1,1029 @@
+package com.redstoner.modules.datamanager;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.server.TabCompleteEvent;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.CommandManager;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.CoreModule;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.Stream)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 10, compatible = 4)
+public final class DataManager implements CoreModule, Listener
+{
+ protected final File dataFolder = new File(Main.plugin.getDataFolder(), "data");
+ protected JSONObject data = new JSONObject();
+ protected JSONObject config_data;
+ protected ArrayList<String> module_index;
+ int old_hash = 0;
+ protected HashMap<String, HashMap<String, Boolean>> states = new HashMap<>();
+ private static DataManager previous_instance = null;
+ protected ArrayList<String> subcommands;
+ protected List<String> scheduled_saves = new ArrayList<>();
+ int task_id;
+
+ @Override
+ public void postEnable()
+ {
+ if (!dataFolder.exists())
+ dataFolder.mkdirs();
+ for (Player p : Bukkit.getOnlinePlayers())
+ {
+ loadData_(p.getUniqueId().toString());
+ }
+ subcommands = new ArrayList<>();
+ subcommands.add("list");
+ subcommands.add("get");
+ subcommands.add("set");
+ subcommands.add("remove");
+ if (previous_instance == null)
+ states.put(getID(Bukkit.getConsoleSender()), new HashMap<String, Boolean>());
+ else
+ {
+ this.states = previous_instance.states;
+ previous_instance = null;
+ }
+ config_data = JsonManager.getObject(new File(dataFolder, "configs.json"));
+ if (config_data == null)
+ config_data = new JSONObject();
+ fixJson();
+ updateIndex();
+ CommandManager.registerCommand(getClass().getResourceAsStream("DataManager.cmd"), this, Main.plugin);
+
+ // Schedule save every ten seconds
+ task_id = Bukkit.getScheduler().runTaskTimerAsynchronously(Main.plugin, new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ for (String id : scheduled_saves)
+ {
+ Object raw = data.get(id);
+ if (raw == null || ((JSONObject) raw).size() == 0)
+ continue;
+ JSONObject json = (JSONObject) raw;
+ JsonManager.save(json, new File(dataFolder, id + ".json"));
+ }
+ scheduled_saves.clear();
+ }
+ }, 0, 20).getTaskId();
+ }
+
+ @Override
+ public void onDisable()
+ {
+ previous_instance = this;
+ for (Player p : Bukkit.getOnlinePlayers())
+ {
+ saveAndUnload(p);
+ }
+ JsonManager.save(config_data, new File(dataFolder, "configs.json"));
+ Bukkit.getScheduler().cancelTask(task_id);
+ }
+
+ @Command(hook = "import_file")
+ public boolean importFile(CommandSender sender, String file, String module)
+ {
+ try
+ {
+ JSONObject object = JsonManager.getObject(new File(file));
+ importObject_(module, object);
+ }
+ catch (Exception e)
+ {
+ getLogger().error("Could not import data!");
+ }
+ return true;
+ }
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event)
+ {
+ loadData_(event.getPlayer().getUniqueId().toString());
+ }
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event)
+ {
+ saveAndUnload(event.getPlayer());
+ }
+
+ public static void loadData(CommandSender sender)
+ {
+ loadData(getID(sender));
+ }
+
+ public static void loadData(String id)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("loadData_", String.class);
+ m.setAccessible(true);
+ m.invoke(mod, id);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ @SuppressWarnings("unchecked")
+ protected synchronized void loadData_(String id)
+ {
+ JSONObject playerData = JsonManager.getObject(new File(dataFolder, id + ".json"));
+ if (playerData == null)
+ playerData = new JSONObject();
+ data.put(id.toString(), playerData);
+ states.put(id.toString(), new HashMap<String, Boolean>());
+ }
+
+ public static Object getOrDefault(CommandSender sender, String key, Object fallback)
+ {
+ return getOrDefault(getID(sender), Utils.getCaller("DataManager"), key, fallback);
+ }
+
+ public static Object getOrDefault(String id, String key, Object fallback)
+ {
+ return getOrDefault(id, Utils.getCaller("DataManager"), key, fallback);
+ }
+
+ public static Object getOrDefault(String id, String module, String key, Object fallback)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("getOrDefault_", String.class, String.class, String.class,
+ Object.class);
+ m.setAccessible(true);
+ return m.invoke(mod, id, module, key, fallback);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ return fallback;
+ }
+
+ protected Object getOrDefault_(String id, String module, String key, Object fallback)
+ {
+ Object o = getData_(id, module, key);
+ return o == null ? fallback : o;
+ }
+
+ public static Object getData(CommandSender sender, String key)
+ {
+ return getData(getID(sender), Utils.getCaller("DataManager"), key);
+ }
+
+ public static Object getData(String id, String key)
+ {
+ return getData(id, Utils.getCaller("DataManager"), key);
+ }
+
+ public static Object getData(String id, String module, String key)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("getData_", String.class, String.class, String.class);
+ m.setAccessible(true);
+ return m.invoke(mod, id, module, key);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ return null;
+ }
+
+ protected Object getData_(String id, String module, String key)
+ {
+ if (data.containsKey(id))
+ {
+ JSONObject moduleData = ((JSONObject) ((JSONObject) data.get(id)).get(module));
+ if (moduleData == null)
+ return null;
+ if (key == null)
+ return moduleData;
+ else
+ return moduleData.get(key);
+ }
+ else
+ return loadAndGet(id, module, key);
+ }
+
+ protected synchronized Object loadAndGet(String id, String module, String key)
+ {
+ JSONObject playerData = JsonManager.getObject(new File(dataFolder, id + ".json"));
+ if (playerData == null)
+ return null;
+ if (key == null)
+ return playerData.get(module);
+ else
+ return ((JSONObject) playerData.get(module)).get(key);
+ }
+
+ public static void setData(CommandSender sender, String key, Object value)
+ {
+ setData(getID(sender), Utils.getCaller("DataManager"), key, value);
+ }
+
+ public static void setData(String id, String key, Object value)
+ {
+ setData(id, Utils.getCaller("DataManager"), key, value);
+ }
+
+ public static void setData(String id, String module, String key, Object value)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("setData_", String.class, String.class, String.class,
+ Object.class);
+ m.setAccessible(true);
+ m.invoke(mod, id, module, key, value);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void setData_(String id, String module, String key, Object value)
+ {
+ if (data.containsKey(id))
+ {
+ JSONObject moduleData = ((JSONObject) ((JSONObject) data.get(id)).get(module));
+ if (moduleData == null)
+ {
+ moduleData = new JSONObject();
+ ((JSONObject) data.get(id)).put(module, moduleData);
+ }
+ if (key == null)
+ setDirectly_(id, module, value);
+ else
+ moduleData.put(key, value);
+ save_(id);
+ }
+ else
+ loadAndSet(id, module, key, value);
+ }
+
+ public static void setDirectly(CommandSender sender, Object value)
+ {
+ setDirectly(getID(sender), Utils.getCaller("DataManager"), value);
+ }
+
+ public static void setDirectly(String id, Object value)
+ {
+ setDirectly(id, Utils.getCaller("DataManager"), value);
+ }
+
+ public static void setDirectly(String id, String module, Object value)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("setDirectly_", String.class, String.class, Object.class);
+ m.setAccessible(true);
+ m.invoke(mod, id, module, value);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void setDirectly_(String id, String module, Object value)
+ {
+ if (data.containsKey(id))
+ {
+ JSONObject playerdata = (JSONObject) data.get(id);
+ playerdata.put(module, value);
+ save_(id);
+ }
+ else
+ loadAndSetDirectly(id, module, value);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected synchronized void loadAndSet(String id, String module, String key, Object value)
+ {
+ File dataFile = new File(dataFolder, id + ".json");
+ JSONObject playerData = JsonManager.getObject(dataFile);
+ if (playerData == null)
+ playerData = new JSONObject();
+ JSONObject moduleData = ((JSONObject) playerData.get(module));
+ if (moduleData == null)
+ {
+ moduleData = new JSONObject();
+ playerData.put(module, moduleData);
+ }
+ moduleData.put(key, value);
+ JsonManager.save(playerData, dataFile);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void loadAndSetDirectly(String id, String module, Object value)
+ {
+ File dataFile = new File(dataFolder, id + ".json");
+ JSONObject playerData = JsonManager.getObject(dataFile);
+ if (playerData == null)
+ playerData = new JSONObject();
+ playerData.put(module, value);
+ JsonManager.save(playerData, dataFile);
+ }
+
+ public static void removeData(CommandSender sender, String key)
+ {
+ removeData(getID(sender), Utils.getCaller("DataManager"), key);
+ }
+
+ public static void removeData(String id, String key)
+ {
+ removeData(id, Utils.getCaller("DataManager"), key);
+ }
+
+ public static void removeData(String id, String module, String key)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("removeData_", String.class, String.class, String.class);
+ m.setAccessible(true);
+ m.invoke(mod, id, module, key);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void removeData_(String id, String module, String key)
+ {
+ if (data.containsKey(id))
+ {
+ JSONObject moduleData = ((JSONObject) ((JSONObject) data.get(id)).get(module));
+ if (moduleData == null)
+ return;
+ moduleData.remove(key);
+ data.put(module, data);
+ save_(id);
+ }
+ else
+ loadAndRemove(id, module, key);
+ }
+
+ protected synchronized void loadAndRemove(String id, String module, String key)
+ {
+ File dataFile = new File(dataFolder, id + ".json");
+ JSONObject playerData = JsonManager.getObject(dataFile);
+ if (playerData == null)
+ return;
+ JSONObject moduleData = ((JSONObject) playerData.get(module));
+ if (moduleData == null)
+ return;
+ moduleData.remove(key);
+ JsonManager.save(playerData, dataFile);
+ }
+
+ public static void importObject(JSONObject object)
+ {
+ importObject(object, Utils.getCaller("DataManager"));
+ }
+
+ public static void importObject(JSONObject object, String module)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("importObject_", String.class, String.class, String.class);
+ m.setAccessible(true);
+ m.invoke(mod, module, object);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ protected void importObject_(String module, JSONObject object)
+ {
+ for (Object o : object.keySet())
+ {
+ String uid = null;
+ if (o instanceof String)
+ uid = (String) o;
+ else if (o instanceof UUID)
+ uid = ((UUID) o).toString();
+ if (uid == null)
+ continue;
+ setDirectly_(uid, module, object.get(o));
+ }
+ }
+
+ public static void migrateAll(String oldName)
+ {
+ migrateAll(oldName, Utils.getCaller("DataManager"));
+ }
+
+ public static void migrateAll(String oldName, String newName)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("migrateAll_", String.class, String.class);
+ m.setAccessible(true);
+ m.invoke(mod, oldName, newName);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ protected void migrateAll_(String oldName, String newName)
+ {
+ for (String s : dataFolder.list(new FilenameFilter()
+ {
+ @Override
+ public boolean accept(File dir, String name)
+ {
+ return name.endsWith(".json");
+ }
+ }))
+ {
+ migrate_(s.replace(".json", ""), oldName, newName);
+ }
+ }
+
+ public static void migrate(String id, String oldName)
+ {
+ migrate(id, oldName, Utils.getCaller("DataManager"));
+ }
+
+ public static void migrate(String id, String oldName, String newName)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("migrate_", String.class, String.class, String.class);
+ m.setAccessible(true);
+ m.invoke(mod, id, oldName, newName);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void migrate_(String id, String oldName, String newName)
+ {
+ if (data.containsKey(id))
+ {
+ data.put(newName, data.get(oldName));
+ data.remove(oldName);
+ save_(id);
+ }
+ else
+ loadAndMigrate(id, oldName, newName);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void loadAndMigrate(String id, String oldName, String newName)
+ {
+ File dataFile = new File(dataFolder, id + ".json");
+ JSONObject data = JsonManager.getObject(dataFile);
+ data.put(newName, data.get(oldName));
+ data.remove(oldName);
+ JsonManager.save(data, dataFile);
+ }
+
+ public static void save(CommandSender sender)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("save_", CommandSender.class);
+ m.setAccessible(true);
+ m.invoke(mod, sender);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ protected void save_(CommandSender sender)
+ {
+ save_(getID(sender));
+ }
+
+ public static void save(String id)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("save_", String.class);
+ m.setAccessible(true);
+ m.invoke(mod, id);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ protected void save_(String id)
+ {
+ scheduled_saves.add(id);
+ }
+
+ protected void saveAndUnload(CommandSender sender)
+ {
+ saveAndUnload(getID(sender));
+ states.remove(getID(sender));
+ }
+
+ protected void saveAndUnload(String id)
+ {
+ save_(id);
+ data.remove(id);
+ }
+
+ private static String getID(CommandSender sender)
+ {
+ String id;
+ if (sender instanceof Player)
+ id = ((Player) sender).getUniqueId().toString();
+ else
+ id = "CONSOLE";
+ return id;
+ }
+
+ public static void setState(CommandSender sender, String key, boolean value)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("setState_", CommandSender.class, String.class, boolean.class);
+ m.setAccessible(true);
+ m.invoke(mod, sender, key, value);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ protected void setState_(CommandSender sender, String key, boolean value)
+ {
+ String id = getID(sender);
+ HashMap<String, Boolean> lstates = states.get(id);
+ lstates.put(key, value);
+ states.put(id, lstates);
+ }
+
+ public static boolean getState(CommandSender sender, String key)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("getState_", CommandSender.class, String.class);
+ m.setAccessible(true);
+ return (boolean) m.invoke(mod, sender, key);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ return false;
+ }
+
+ protected boolean getState_(CommandSender sender, String key)
+ {
+ String id = getID(sender);
+ HashMap<String, Boolean> lstates = states.get(id);
+ if (lstates == null)
+ return false;
+ return lstates.containsKey(key) ? lstates.get(key) : false;
+ }
+
+ protected boolean hasConfigChanged()
+ {
+ return old_hash != config_data.hashCode();
+ }
+
+ protected void updateIndex()
+ {
+ if (!hasConfigChanged())
+ return;
+ old_hash = config_data.hashCode();
+ module_index = new ArrayList<>();
+ if (config_data.size() > 0)
+ {
+ for (Object key : config_data.keySet())
+ module_index.add(key.toString());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void fixJson()
+ {
+ for (Object key : config_data.keySet())
+ {
+ JSONObject json = (JSONObject) config_data.get(key);
+ for (Object key2 : json.keySet())
+ {
+ Object o = json.get(key2);
+ if (!(o instanceof ConfigEntry))
+ json.put(key2, new ConfigEntry((JSONObject) o));
+ }
+ config_data.put(key, json);
+ }
+ }
+
+ private List<String> subsetWhereStartsWith(List<String> list, String prefix)
+ {
+ ArrayList<String> subset = new ArrayList<>();
+ if (prefix == null || prefix.equals(""))
+ return list;
+ for (String s : list)
+ if (s.toLowerCase().startsWith(prefix.toLowerCase()))
+ subset.add(s);
+ return subset;
+ }
+
+ @SuppressWarnings("unchecked")
+ @EventHandler
+ public void onTabComplete(TabCompleteEvent event)
+ {
+ if (event.getBuffer().toLowerCase().matches("^/?settings? .*")
+ || event.getBuffer().toLowerCase().matches("^/?configs? .*"))
+ {
+ boolean argument_complete = event.getBuffer().endsWith(" ");
+ String[] arguments = event.getBuffer().split(" ");
+ event.setCompletions(new ArrayList<String>());
+ if (arguments.length == 1 || (arguments.length == 2 && !argument_complete))
+ event.setCompletions(subsetWhereStartsWith(subcommands, arguments.length >= 2 ? arguments[1] : ""));
+ else if (arguments.length == 2 || (arguments.length == 3 && !argument_complete))
+ {
+ switch (arguments[1].toLowerCase())
+ {
+ case "list":
+ case "get":
+ case "set":
+ {
+ event.setCompletions(
+ subsetWhereStartsWith(module_index, arguments.length == 3 ? arguments[2] : ""));
+ break;
+ }
+ }
+ }
+ else if ((arguments.length == 3 && argument_complete) || (arguments.length == 4 && !argument_complete))
+ {
+ switch (arguments[1].toLowerCase())
+ {
+ case "get":
+ case "set":
+ {
+ Object o = config_data.get(arguments[2]);
+ if (o == null)
+ break;
+ event.setCompletions(subsetWhereStartsWith(new ArrayList<String>(((JSONObject) o).keySet()),
+ arguments.length == 4 ? arguments[3] : ""));
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (arguments[1].toLowerCase().equals("set"))
+ {
+ Object o = config_data.get(arguments[2]);
+ if (o == null)
+ return;
+ Object o2 = ((JSONObject) o).get(arguments[3]);
+ if (o2 == null)
+ return;
+ event.setCompletions(subsetWhereStartsWith(Arrays.asList(((ConfigEntry) o2).getCompleteOptions()),
+ arguments.length > 4 ? String.join(" ", Arrays.copyOfRange(arguments, 4, arguments.length))
+ : ""));
+ }
+ }
+ }
+ }
+
+ @Command(hook = "config_list")
+ public boolean list(CommandSender sender)
+ {
+ getLogger().message(sender, Arrays.toString(module_index.toArray(new String[] {})));
+ return true;
+ }
+
+ @Command(hook = "config_list2")
+ public boolean list(CommandSender sender, String module)
+ {
+ Object o = config_data.get(module);
+ if (o == null)
+ {
+ getLogger().message(sender, "This module has not registered any settings.");
+ }
+ else
+ {
+ ArrayList<String> entries = new ArrayList<>();
+ JSONObject json = (JSONObject) o;
+ for (Object key : json.keySet())
+ {
+ String entry = key.toString();
+ entries.add("§e" + entry + "§7");
+ }
+ getLogger().message(sender, "The module §e" + module + "§7 has the following config settings: ",
+ Arrays.toString(entries.toArray(new String[] {})));
+ }
+ return true;
+ }
+
+ @Command(hook = "config_get")
+ public boolean get(CommandSender sender, String module, String key)
+ {
+ getLogger().message(sender, new String[] {"§e" + module + "." + key + "§7 currently holds the value:",
+ getConfigOrDefault_(module, key, "<empty>").toString()});
+ return true;
+ }
+
+ @Command(hook = "config_set")
+ public boolean set(CommandSender sender, String module, String key, String value)
+ {
+ if (setConfig_(module, key, value))
+ {
+ getLogger().message(sender, "Successfully changed the value for §e" + module + "." + key);
+ }
+ else
+ {
+ getLogger().message(sender, true,
+ "§7\"§e" + value + "§7\" is not a valid value for setting §e" + module + "." + key);
+ }
+ return true;
+ }
+
+ @Command(hook = "config_remove_all")
+ public boolean remove_all(CommandSender sender, String module)
+ {
+ if (removeAllConfig_(module))
+ getLogger().message(sender, "Successfully deleted all config entries for module §e" + module + "§7!");
+ else
+ getLogger().message(sender, true, "Could not delete all config entries for module §e" + module + "§7!");
+ return true;
+ }
+
+ public static Object getConfigOrDefault(String key, Object fallback)
+ {
+ return getConfigOrDefault(Utils.getCaller("DataManager"), key, fallback);
+ }
+
+ public static Object getConfigOrDefault(String module, String key, Object fallback)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("getConfigOrDefault_", String.class, String.class,
+ Object.class);
+ m.setAccessible(true);
+ return m.invoke(mod, module, key, fallback);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ return fallback;
+ }
+
+ protected Object getConfigOrDefault_(String module, String key, Object fallback)
+ {
+ Object o = getConfigData_(module, key);
+ return o == null ? fallback : o;
+ }
+
+ protected Object getConfigData_(String module, String key)
+ {
+ module = module.toLowerCase();
+ Object o = config_data.get(module);
+ if (o == null)
+ return null;
+ else
+ {
+ JSONObject json = (JSONObject) o;
+ Object o2 = json.get(key);
+ if (o2 == null)
+ return null;
+ return ((ConfigEntry) o2).getValue();
+ }
+ }
+
+ protected ConfigEntry getConfigEntry_(String module, String key)
+ {
+ module = module.toLowerCase();
+ Object o = config_data.get(module);
+ if (o == null)
+ return null;
+ else
+ {
+ JSONObject json = (JSONObject) o;
+ return (ConfigEntry) json.get(key);
+ }
+ }
+
+ public static void setConfig(String key, String value)
+ {
+ setConfig(Utils.getCaller("DataManager"), key, value, null);
+ }
+
+ public static void setConfig(String key, String value, String[] complete_options)
+ {
+ setConfig(Utils.getCaller("DataManager"), key, value, complete_options);
+ }
+
+ public static void setConfig(String module, String key, String value, String[] complete_options)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("setConfig_", String.class, String.class, String.class,
+ String[].class);
+ m.setAccessible(true);
+ m.invoke(mod, module, key, value, complete_options);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ @SuppressWarnings("unchecked")
+ protected boolean setConfig_(String module, String key, String value)
+ {
+ module = module.toLowerCase();
+ ConfigEntry entry = getConfigEntry_(module, key);
+ if (entry == null)
+ entry = new ConfigEntry(value, null);
+ if (entry.attemptSet(value))
+ {
+ Object o = config_data.get(module);
+ JSONObject json;
+ if (o == null)
+ json = new JSONObject();
+ else
+ json = (JSONObject) o;
+ json.put(key, entry);
+ config_data.put(module, json);
+ updateIndex();
+ return true;
+ }
+ else
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void setConfig_(String module, String key, String value, String[] complete_options)
+ {
+ module = module.toLowerCase();
+ ConfigEntry entry = new ConfigEntry(value, complete_options);
+ Object o = config_data.get(module);
+ JSONObject json;
+ if (o == null)
+ json = new JSONObject();
+ else
+ json = (JSONObject) o;
+ json.put(key, entry);
+ config_data.put(module, json);
+ updateIndex();
+ }
+
+ public static boolean removeConfig(String key)
+ {
+ return removeConfig(Utils.getCaller("DataManager"), key);
+ }
+
+ public static boolean removeConfig(String module, String key)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("DataManager");
+ Method m = mod.getClass().getDeclaredMethod("removeConfig_", String.class, String.class);
+ m.setAccessible(true);
+ return (boolean) m.invoke(mod, module, key);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ return false;
+ }
+
+ @SuppressWarnings("unchecked")
+ protected boolean removeConfig_(String module, String key)
+ {
+ module = module.toLowerCase();
+ if (key == null)
+ return removeAllConfig_(module);
+ Object o = config_data.get(module);
+ JSONObject json;
+ if (o == null)
+ return false;
+ else
+ json = (JSONObject) o;
+ json.remove(key);
+ if (json.size() == 0)
+ config_data.remove(module);
+ else
+ config_data.put(module, json);
+ updateIndex();
+ return true;
+ }
+
+ protected boolean removeAllConfig_(String module)
+ {
+ module = module.toLowerCase();
+ if (config_data.remove(module) == null)
+ return false;
+ updateIndex();
+ return true;
+ }
+}
+
+class ConfigEntry
+{
+ private String value;
+ private String[] complete_options;
+
+ public ConfigEntry(String value, String[] complete_options)
+ {
+ this.value = value;
+ this.complete_options = complete_options;
+ }
+
+ @SuppressWarnings("unchecked")
+ public ConfigEntry(JSONObject json)
+ {
+ this(json.get("value").toString(),
+ (String[]) ((JSONArray) json.get("complete_options")).toArray(new String[] {}));
+ }
+
+ protected boolean attemptSet(String value)
+ {
+ if (complete_options == null || complete_options.length == 0)
+ {
+ this.value = value;
+ return true;
+ }
+ else
+ {
+ for (String s : complete_options)
+ {
+ if (s.equals(value))
+ {
+ this.value = value;
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ protected String[] getCompleteOptions()
+ {
+ return complete_options;
+ }
+
+ protected String getValue()
+ {
+ return value;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "{\"value\":\"" + value + "\",\"complete_options\":"
+ + (complete_options == null || complete_options.length == 0 ? "[]"
+ : "[\"" + String.join("\",\"", complete_options) + "\"]")
+ + "}";
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/discord/Discord.cmd b/src/main/java/com/redstoner/modules/discord/Discord.cmd
new file mode 100644
index 0000000..a3e1af5
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/discord/Discord.cmd
@@ -0,0 +1,8 @@
+command discord {
+ [empty] {
+ perm utils.external.discord
+ help Info, Register Instructions, and Token for the Discord;
+ run discord;
+ type player;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/discord/Discord.java b/src/main/java/com/redstoner/modules/discord/Discord.java
new file mode 100644
index 0000000..9d87bc0
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/discord/Discord.java
@@ -0,0 +1,118 @@
+package com.redstoner.modules.discord;
+
+import java.io.File;
+import java.security.SecureRandom;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.json.simple.JSONObject;
+
+import net.nemez.chatapi.click.Message;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 0, compatible = 4)
+public class Discord implements Module {
+
+ private final String FILENAME = "discordTokens.json";
+ private final String DNE_LINK = "dne://";
+
+ private JSONObject discordTables;
+ private JSONObject byToken;
+ private JSONObject byUUID;
+
+ private String joinLink;
+ private File savefile;
+
+ private final String tokenCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ private SecureRandom rnd = new SecureRandom();
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean onEnable() {
+ savefile = new File(Main.plugin.getDataFolder(), FILENAME);
+
+ discordTables = JsonManager.getObject(savefile);
+
+ if (discordTables == null) {
+ discordTables = new JSONObject();
+ discordTables.put("joinLink", DNE_LINK);
+ save();
+ }
+
+ Object joinLinkObject = discordTables.get("joinLink");
+
+ if (joinLinkObject == null || ((String) joinLinkObject).equals(DNE_LINK)) {
+ getLogger().error("Missing Join Link. Set: \"joinLink\" to \"_joinLink_\" in the discordTokens.json file.");
+ return false;
+ }
+
+ joinLink = (String) joinLinkObject;
+
+ Object byTokenObject = discordTables.get("byToken");
+
+ if (byTokenObject == null) {
+ discordTables.put("byToken", new JSONObject());
+ discordTables.put("byUUID", new JSONObject());
+ }
+
+ byToken = (JSONObject) discordTables.get("byToken");
+ byUUID = (JSONObject) discordTables.get("byUUID");
+
+ return true;
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "discord")
+ public void discord(CommandSender sender) {
+ Player p = (Player) sender;
+ String pUUID = p.getUniqueId().toString();
+
+ Object tokenObject = byUUID.get(pUUID);
+ String token = tokenObject == null? null : (String) tokenObject;
+
+ if (token == null) {
+
+ token = randomToken(8);
+ Object UUIDObject = byToken.get(token);
+
+ while (UUIDObject != null) {
+ token = randomToken(8);
+ UUIDObject = byToken.get(token);
+ }
+ byUUID.put(pUUID, token);
+ byToken.put(token, pUUID);
+ save();
+ }
+
+ new Message(sender, null).appendText("\n&cRedstoner&7 has a &2Discord&7 Now! \nClick ")
+ .appendLinkHover("&e" + joinLink, joinLink, "&aClick to Join")
+ .appendText("&7 to join. \n\nTo sync you rank, copy ")
+ .appendSuggestHover("&e" + token, token, "&aClick to Copy")
+ .appendText("&7 into &3#rank-sync&7.\n")
+ .send();
+ }
+
+ private String randomToken(int length){
+ StringBuilder sb = new StringBuilder( length );
+ for( int i = 0; i < length; i++ )
+ sb.append( tokenCharacters.charAt( rnd.nextInt(tokenCharacters.length()) ) );
+ return sb.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ private void save() {
+
+ discordTables.put("byToken", byToken);
+ discordTables.put("byUUID", byUUID);
+ JsonManager.save(discordTables, savefile);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/friends/Friends.cmd b/src/main/java/com/redstoner/modules/friends/Friends.cmd
new file mode 100644
index 0000000..ea205c9
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/friends/Friends.cmd
@@ -0,0 +1,38 @@
+command friends {
+ add [string:name] {
+ run add name;
+ help Adds a friend to your friendlist.;
+ perm utils.friends;
+ }
+ add [string:name] [string:group] {
+ run add_grouped name group;
+ help Adds a friend to a group of friends;
+ perm utils.friends.groups;
+ }
+ remove [string:name] {
+ run del name;
+ help Removes a friend from your friendlist.;
+ perm utils.friends;
+ }
+ remove [string:name] [string:group] {
+ run del_grouped name group;
+ help Removes a friend from a group of friends;
+ perm utils.friends.groups;
+ }
+ list {
+ run list;
+ help Shows a list of all your friends.;
+ perm utils.friends;
+ }
+ list [string:group] {
+ run list_group group;
+ help Shows a list of all friends in that group.;
+ perm utils.friends.groups;
+ }
+ groups {
+ run list_groups;
+ help Shows all your friend groups that have at least one person in them.;
+ perm utils.friends.groups;
+ }
+ type player;
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/friends/Friends.java b/src/main/java/com/redstoner/modules/friends/Friends.java
new file mode 100644
index 0000000..2eb9728
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/friends/Friends.java
@@ -0,0 +1,360 @@
+package com.redstoner.modules.friends;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Set;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.Sound;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.CoreModule;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+@AutoRegisterListener
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 0, compatible = 4)
+public class Friends implements CoreModule
+{
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onPlayerJoin(PlayerJoinEvent e)
+ {
+ JSONArray friended_by = (JSONArray) DataManager.getOrDefault(e.getPlayer(), "friended_by", new JSONArray());
+ for (Object obj : friended_by)
+ {
+ UUID uuid = UUID.fromString((String) obj);
+ Player p = Bukkit.getPlayer(uuid);
+ if (p != null && p.canSee(e.getPlayer()))
+ {
+ getLogger().message(p, "Your friend &e" + e.getPlayer().getDisplayName() + "&7 just joined!");
+ p.playSound(p.getLocation(), Sound.ENTITY_CHICKEN_EGG, 1, 1);
+ }
+ }
+ JSONArray notifications = (JSONArray) DataManager.getOrDefault(e.getPlayer(), "scheduled_notifications",
+ new JSONArray());
+ for (Object obj : notifications)
+ getLogger().message(e.getPlayer(), (String) obj);
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onPlayerLeave(PlayerQuitEvent e)
+ {
+ JSONArray friended_by = (JSONArray) DataManager.getOrDefault(e.getPlayer(), "friended_by", new JSONArray());
+ for (Object obj : friended_by)
+ {
+ UUID uuid = UUID.fromString((String) obj);
+ Player p = Bukkit.getPlayer(uuid);
+ if (p != null && p.canSee(e.getPlayer()))
+ {
+ getLogger().message(p, "Your friend &e" + e.getPlayer().getDisplayName() + "&7 just left!");
+ p.playSound(p.getLocation(), Sound.ENTITY_CHICKEN_EGG, 1, 1);
+ }
+ }
+ }
+
+ @SuppressWarnings({"unchecked", "deprecation"})
+ @Command(hook = "add")
+ public boolean add(CommandSender sender, String target)
+ {
+ if (target.equalsIgnoreCase("CONSOLE"))
+ {
+ getLogger().message(sender, true, "You can't add console to your friends!");
+ return true;
+ }
+ OfflinePlayer p = Bukkit.getPlayer(target);
+ if (p == null)
+ p = Bukkit.getOfflinePlayer(target);
+ if (p == null)
+ {
+ getLogger().message(sender, true, "That player couldn't be found!");
+ return true;
+ }
+ JSONArray friends = ((JSONArray) DataManager.getOrDefault(sender, "friends", new JSONArray()));
+ if (friends.contains(p.getUniqueId().toString()))
+ {
+ getLogger().message(sender, true, "You are already friends with this person!");
+ return true;
+ }
+ friends.add(p.getUniqueId().toString());
+ DataManager.save(sender);
+ JSONArray friended_by = ((JSONArray) DataManager.getOrDefault(p.getUniqueId().toString(), "friended_by",
+ new JSONArray()));
+ friended_by.add(getID(sender));
+ DataManager.save(p.getUniqueId().toString());
+ getLogger().message(sender, "You are now friends with &e" + p.getName() + "&7!");
+ if (p instanceof Player)
+ {
+ getLogger().message((Player) p, "&e" + Utils.getName(sender) + "&7 added you as a friend!");
+ }
+ else
+ {
+ JSONArray notifications = (JSONArray) DataManager.getOrDefault(p.getUniqueId().toString(),
+ "scheduled_notifications", new JSONArray());
+ notifications.add("&e" + Utils.getName(sender) + "&7 added you as a friend!");
+ notifications.remove("&e" + Utils.getName(sender) + "&7 removed you as a friend!");
+ DataManager.setData(p.getUniqueId().toString(), "scheduled_notifications", notifications);
+ }
+ return true;
+ }
+
+ @SuppressWarnings({"deprecation", "unchecked"})
+ @Command(hook = "add_grouped")
+ public boolean add_grouped(CommandSender sender, String target, String group)
+ {
+ if (target.equalsIgnoreCase("CONSOLE"))
+ {
+ getLogger().message(sender, true, "You can't add console to your friends!");
+ return true;
+ }
+ OfflinePlayer p = Bukkit.getPlayer(target);
+ if (p == null)
+ p = Bukkit.getOfflinePlayer(target);
+ if (p == null)
+ {
+ getLogger().message(sender, true, "That player couldn't be found!");
+ return true;
+ }
+ JSONArray friends = ((JSONArray) DataManager.getOrDefault(sender, "groups." + group, new JSONArray()));
+ if (friends.contains(p.getUniqueId().toString()))
+ {
+ getLogger().message(sender, true, "This person already is part of that friendsgroup!");
+ return true;
+ }
+ friends.add(p.getUniqueId().toString());
+ DataManager.save(sender);
+ getLogger().message(sender, "&e" + p.getName() + "&7 is now part of the group &e" + group + "&7!");
+ if (p instanceof Player)
+ {
+ getLogger().message((Player) p,
+ "&e" + Utils.getName(sender) + " &7added you to their friendsgroup &e" + group + "&7!");
+ }
+ else
+ {
+ JSONArray notifications = (JSONArray) DataManager.getOrDefault(p.getUniqueId().toString(),
+ "scheduled_notifications", new JSONArray());
+ notifications.add("&e" + Utils.getName(sender) + " &7added you to their friendsgroup &e" + group + "&7!");
+ notifications
+ .remove("&e" + Utils.getName(sender) + " &7removed you from their friendsgroup &e" + group + "&7!");
+ DataManager.setData(p.getUniqueId().toString(), "scheduled_notifications", notifications);
+ }
+ return true;
+ }
+
+ @SuppressWarnings({"deprecation", "unchecked"})
+ @Command(hook = "del")
+ public boolean del(CommandSender sender, String target)
+ {
+ if (target.equalsIgnoreCase("CONSOLE"))
+ {
+ getLogger().message(sender, true, "You can't add console to your friends!");
+ return true;
+ }
+ OfflinePlayer p = Bukkit.getPlayer(target);
+ if (p == null)
+ p = Bukkit.getOfflinePlayer(target);
+ if (p == null)
+ {
+ getLogger().message(sender, true, "That player couldn't be found!");
+ return true;
+ }
+ JSONArray friends = ((JSONArray) DataManager.getOrDefault(sender, "friends", new JSONArray()));
+ if (friends.contains(p.getUniqueId().toString()))
+ {
+ getLogger().message(sender, true, "You are already friends with this person!");
+ return true;
+ }
+ friends.remove(p.getUniqueId().toString());
+ DataManager.save(sender);
+ JSONArray friended_by = ((JSONArray) DataManager.getOrDefault(p.getUniqueId().toString(), "friended_by",
+ new JSONArray()));
+ friended_by.remove(getID(sender));
+ DataManager.save(p.getUniqueId().toString());
+ getLogger().message(sender, "You are now friends with &e" + p.getName() + "&7!");
+ if (p instanceof Player)
+ {
+ getLogger().message((Player) p, "&e" + Utils.getName(sender) + "&7 added you as a friend!");
+ }
+ else
+ {
+ JSONArray notifications = (JSONArray) DataManager.getOrDefault(p.getUniqueId().toString(),
+ "scheduled_notifications", new JSONArray());
+ notifications.add("&e" + Utils.getName(sender) + "&7 removed you as a friend!");
+ notifications.remove("&e" + Utils.getName(sender) + "&7 added you as a friend!");
+ DataManager.setData(p.getUniqueId().toString(), "scheduled_notifications", notifications);
+ }
+ return true;
+ }
+
+ @SuppressWarnings({"deprecation", "unchecked"})
+ @Command(hook = "del_grouped")
+ public boolean del_grouped(CommandSender sender, String target, String group)
+ {
+ if (target.equalsIgnoreCase("CONSOLE"))
+ {
+ getLogger().message(sender, true, "You can't add console to your friends!");
+ return true;
+ }
+ OfflinePlayer p = Bukkit.getPlayer(target);
+ if (p == null)
+ p = Bukkit.getOfflinePlayer(target);
+ if (p == null)
+ {
+ getLogger().message(sender, true, "That player couldn't be found!");
+ return true;
+ }
+ JSONArray friends = ((JSONArray) DataManager.getOrDefault(sender, "groups." + group, new JSONArray()));
+ if (friends.contains(p.getUniqueId().toString()))
+ {
+ getLogger().message(sender, true, "This person already is part of that friendsgroup!");
+ return true;
+ }
+ friends.add(p.getUniqueId().toString());
+ DataManager.save(sender);
+ getLogger().message(sender, "&e" + p.getName() + "&7 is now part of the group &e" + group + "&7!");
+ if (p instanceof Player)
+ {
+ getLogger().message((Player) p,
+ "&e" + Utils.getName(sender) + " &7added you to their friendsgroup &e" + group + "&7!");
+ }
+ else
+ {
+ JSONArray notifications = (JSONArray) DataManager.getOrDefault(p.getUniqueId().toString(),
+ "scheduled_notifications", new JSONArray());
+ notifications
+ .add("&e" + Utils.getName(sender) + " &7removed you from their friendsgroup &e" + group + "&7!");
+ notifications
+ .remove("&e" + Utils.getName(sender) + " &7added you to their friendsgroup &e" + group + "&7!");
+ DataManager.setData(p.getUniqueId().toString(), "scheduled_notifications", notifications);
+ }
+ return true;
+ }
+
+ @Command(hook = "list")
+ public boolean list(CommandSender sender)
+ {
+ JSONArray friends = (JSONArray) DataManager.getOrDefault(sender, "friends", new JSONArray());
+ if (friends.size() == 0)
+ {
+ getLogger().message(sender, true, "You didn't add anyone to your friendslist yet.");
+ }
+ else
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Object o : friends.toArray())
+ {
+ UUID id = UUID.fromString((String) o);
+ Player p = Bukkit.getPlayer(id);
+ if (p != null)
+ sb.append(p.getDisplayName() + "&7, ");
+ else
+ sb.append("&9" + Bukkit.getOfflinePlayer(id).getName() + "&7, ");
+ }
+ String out = sb.toString().replaceAll(", $", "");
+ getLogger().message(sender, "You have a total of &e" + friends.size() + "&7 friends:", out);
+ }
+ return true;
+ }
+
+ @Command(hook = "list_group")
+ public boolean list_group(CommandSender sender, String group)
+ {
+ JSONArray friends = (JSONArray) DataManager.getOrDefault(sender, "group." + group, new JSONArray());
+ if (friends.size() == 0)
+ {
+ getLogger().message(sender, true, "You didn't add anyone to this group yet.");
+ }
+ else
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Object o : friends.toArray())
+ {
+ UUID id = UUID.fromString((String) o);
+ Player p = Bukkit.getPlayer(id);
+ if (p != null)
+ sb.append(p.getDisplayName() + "&7, ");
+ else
+ sb.append("&9" + Bukkit.getOfflinePlayer(id).getName() + "&7, ");
+ }
+ String out = sb.toString().replaceAll(", $", "");
+ getLogger().message(sender, "You have a total of &e" + friends.size() + "&7 friends added to this group:", out);
+ }
+ return true;
+ }
+
+ @Command(hook = "list_groups")
+ public boolean list_groups(CommandSender sender)
+ {
+ JSONObject raw = (JSONObject) DataManager.getOrDefault(sender, null, new JSONObject());
+ Set<?> keys = raw.keySet();
+ if (keys.size() == 0 || (keys.contains("friends") && keys.size() == 1))
+ {
+ getLogger().message(sender, true, "You don't have any custom groups made yet.");
+ return true;
+ }
+ else
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Object o : keys)
+ {
+ sb.append("&e" + (String) o + "&7, ");
+ }
+ String out = sb.toString().replaceAll(", $", "");
+ getLogger().message(sender, "", out);
+ }
+ return true;
+ }
+
+ public static boolean isFriend(CommandSender player, CommandSender friend)
+ {
+ return isFriend(player, friend, null);
+ }
+
+ public static boolean isFriend(CommandSender player, CommandSender friend, String condition)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("Friends");
+ Method m = mod.getClass().getDeclaredMethod("isFriend_", String.class);
+ return (boolean) m.invoke(mod, player, friend, condition);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ return false;
+ }
+
+ protected boolean isFriend_(CommandSender player, CommandSender friend, String group)
+ {
+ if (group == null)
+ group = "friends";
+ else if (!group.startsWith("group."))
+ group = "group." + group;
+ JSONArray array = (JSONArray) DataManager.getOrDefault(player, group, new JSONArray());
+ return array.contains(getID(friend));
+ }
+
+ private final String getID(CommandSender sender)
+ {
+ if (sender instanceof Player)
+ return ((Player) sender).getUniqueId().toString();
+ else
+ return sender.getName();
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/ignore/Ignore.cmd b/src/main/java/com/redstoner/modules/ignore/Ignore.cmd
new file mode 100644
index 0000000..382846b
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/ignore/Ignore.cmd
@@ -0,0 +1,22 @@
+command ignore {
+ [string:player] {
+ perm utils.ignore;
+ run ignore player;
+ type player;
+ help Ignores or Unignores a player.;
+ }
+ [empty] {
+ perm utils.ignore;
+ run list;
+ type player;
+ help Lists everyone you ignore.;
+ }
+}
+command unignore {
+ [string:player] {
+ perm utils.ignore;
+ run unignore player;
+ type player;
+ help Unignore a player.;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/ignore/Ignore.java b/src/main/java/com/redstoner/modules/ignore/Ignore.java
new file mode 100644
index 0000000..c830700
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/ignore/Ignore.java
@@ -0,0 +1,159 @@
+package com.redstoner.modules.ignore;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.json.simple.JSONArray;
+
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.Command.AsyncType;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.BroadcastFilter;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+import net.nemez.chatapi.click.Message;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 0, revision = 0, compatible = 4)
+public class Ignore implements Module
+{
+
+ @Command(hook = "unignore", async = AsyncType.ALWAYS)
+ public boolean unignore(CommandSender sender, String player)
+ {
+ return ignore(sender, player, false);
+ }
+
+ @Command(hook = "ignore", async = AsyncType.ALWAYS)
+ public boolean ignore(CommandSender sender, String player)
+ {
+ return ignore(sender, player, true);
+ }
+
+ @Command(hook = "list", async = AsyncType.ALWAYS)
+ public boolean list(CommandSender sender)
+ {
+ getLogger().message(sender, "§7You are currently ignoring:");
+
+ JSONArray ignores = (JSONArray) DataManager.getOrDefault(sender, "ignores", new JSONArray());
+
+ if (ignores.isEmpty())
+ {
+ new Message(sender, null).appendText(" §7Nobody \\o/").send();
+ return true;
+ }
+
+ String players;
+ OfflinePlayer pi = Bukkit.getOfflinePlayer(UUID.fromString((String) ignores.get(0)));
+ players = " §3" + pi.getName() + "§7";
+
+ for (int i = 1; i < ignores.size(); i++)
+ {
+ OfflinePlayer p = Bukkit.getOfflinePlayer(UUID.fromString((String) ignores.get(i)));
+ players += ", §3" + p.getName() + "§7";
+ }
+
+ Message m = new Message(sender, null);
+ m.appendText(players);
+ m.send();
+ return true;
+ }
+
+ @SuppressWarnings({"unchecked", "deprecation"})
+ public boolean ignore(CommandSender sender, String player, boolean allowIgnore)
+ {
+ JSONArray ignores = (JSONArray) DataManager.getOrDefault(sender, "ignores", new JSONArray());
+
+ Player p = Utils.isUUID(player) ? Bukkit.getPlayer(UUID.fromString(player)) : Bukkit.getPlayer(player);
+
+ OfflinePlayer op = Utils.isUUID(player) ? Bukkit.getOfflinePlayer(UUID.fromString(player))
+ : Bukkit.getOfflinePlayer(player);
+
+ String pName = p != null ? p.getDisplayName() : op.getName();
+ String pUUID = p != null ? p.getUniqueId().toString() : op.getUniqueId().toString();
+ String sUUID = ((Player) sender).getUniqueId().toString();
+
+ if (pUUID.equals(sUUID))
+ {
+ getLogger().message(sender, true, "§7You can't ignore yourself :P");
+ return true;
+ }
+
+ if (ignores.contains(pUUID))
+ {
+ ignores.remove(pUUID);
+ getLogger().message(sender, "§7You are no longer ignoring §3" + pName + "§7.");
+ }
+ else if (!allowIgnore)
+ {
+ getLogger().message(sender, "§7You weren't ignoring §3" + pName + "§7.");
+ }
+ else
+ {
+ ignores.add(pUUID);
+ getLogger().message(sender, "§7You are now ignoring §3" + pName + "§7.");
+ }
+ DataManager.setData(sender, "ignores", ignores);
+ return true;
+
+ }
+
+ public static BroadcastFilter getIgnoredBy(CommandSender sender)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("Ignore");
+ Method m = mod.getClass().getDeclaredMethod("_getIgnoredBy", CommandSender.class);
+ m.setAccessible(true);
+ return (BroadcastFilter) m.invoke(mod, sender);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ return null;
+ }
+
+ @SuppressWarnings("unused")
+ private BroadcastFilter _getIgnoredBy(CommandSender sender)
+ {
+ return new BroadcastFilter()
+ {
+
+ private final String sUUID = sender instanceof Player ? ((Player) sender).getUniqueId().toString()
+ : "CONSOLE";
+
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ if (sUUID.equals("CONSOLE"))
+ return true;
+
+ if (recipient instanceof Player)
+ {
+ Player player = (Player) recipient;
+
+ if (sender.hasPermission("utils.ignore.override"))
+ return true;
+
+ JSONArray ignores = (JSONArray) DataManager.getOrDefault(recipient, "ignores", new JSONArray());
+ return !ignores.contains(sUUID);
+ }
+ else
+ return true;
+ }
+ };
+ }
+
+}
diff --git a/src/main/java/com/redstoner/modules/lagchunks/LagChunks.cmd b/src/main/java/com/redstoner/modules/lagchunks/LagChunks.cmd
new file mode 100644
index 0000000..142a437
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/lagchunks/LagChunks.cmd
@@ -0,0 +1,19 @@
+command lc {
+ perm utils.lagchunks;
+
+ list {
+ run list_cmd;
+ help re-lists already scanned chunks;
+ }
+
+ [int:amount] {
+ run scan_cmd amount;
+ help scans for laggy chunks;
+ }
+
+ tp [int:number] {
+ run tp number;
+ help teleports to the specified chunk;
+ type player;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/lagchunks/LagChunks.java b/src/main/java/com/redstoner/modules/lagchunks/LagChunks.java
new file mode 100644
index 0000000..1debf12
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/lagchunks/LagChunks.java
@@ -0,0 +1,82 @@
+package com.redstoner.modules.lagchunks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.Command.AsyncType;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class LagChunks implements Module
+{
+ private List<LaggyChunk> laggyChunks = new ArrayList<LaggyChunk>();
+
+ private void scan(int amount)
+ {
+ laggyChunks.clear();
+ for (World world : Bukkit.getServer().getWorlds())
+ {
+ for (Chunk chunk : world.getLoadedChunks())
+ {
+ if (chunk.getEntities().length > amount)
+ {
+ Location entLoc = chunk.getEntities()[0].getLocation();
+ laggyChunks.add(new LaggyChunk(entLoc.getBlockX(), entLoc.getBlockY(), entLoc.getBlockZ(), world,
+ chunk.getEntities().length));
+ }
+ }
+ }
+ }
+
+ @Command(hook = "list_cmd")
+ public void list(CommandSender sender)
+ {
+ if (laggyChunks.size() > 0)
+ {
+ ArrayList<String> message = new ArrayList<String>();
+ for (LaggyChunk lc : laggyChunks)
+ {
+ message.add("§b[§a" + laggyChunks.indexOf(lc) + "§b]: §a" + lc.x + "§7, §a" + lc.y + "§7, §a" + lc.z
+ + " §7(" + lc.world.getName() + ") §a- §b" + lc.amount + " entities");
+ }
+ message.add("§2-------------------");
+ getLogger().message(sender, message.toArray(new String[] {}));
+ }
+ else
+ getLogger().message(sender, true, "Couldn't find any chunks with that many entities.");
+ }
+
+ @Command(hook = "scan_cmd", async = AsyncType.ALWAYS)
+ public void scan_cmd(CommandSender sender, int amount)
+ {
+ scan(amount);
+ list(sender);
+ }
+
+ @Command(hook = "tp")
+ public void tp(CommandSender sender, int number)
+ {
+ Player player = (Player) sender;
+ if (number < laggyChunks.size())
+ {
+ player.teleport(laggyChunks.get(number).getLocation());
+ getLogger().message(player, "§aTeleported to chunk " + number + "!");
+ }
+ else
+ {
+ getLogger().message(sender, true, "§4Invalid chunk number! Use §e/lc list §4to show laggy chunks!");
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/lagchunks/LaggyChunk.java b/src/main/java/com/redstoner/modules/lagchunks/LaggyChunk.java
new file mode 100644
index 0000000..3ff4d6f
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/lagchunks/LaggyChunk.java
@@ -0,0 +1,21 @@
+package com.redstoner.modules.lagchunks;
+
+import org.bukkit.Location;
+import org.bukkit.World;
+
+public class LaggyChunk {
+ public final int x, y, z, amount;
+ public final World world;
+
+ public LaggyChunk(int x, int y, int z, World world, int amount) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.world = world;
+ this.amount = amount;
+ }
+
+ public Location getLocation() {
+ return new Location(world, x, y, z);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/list/List.cmd b/src/main/java/com/redstoner/modules/list/List.cmd
new file mode 100644
index 0000000..f4caf02
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/list/List.cmd
@@ -0,0 +1,38 @@
+command list {
+ alias ls;
+ alias elist;
+ alias online;
+ alias eonline;
+ alias playerlist;
+ alias eplayerlist;
+ alias plist;
+ alias eplist;
+ alias who;
+ alias ewho;
+ [empty] {
+ run list;
+ help Shows all online players sorted by rank.;
+ }
+ [string:rank...] {
+ run list_rank rank;
+ help Shows all online players of the specified rank(s);
+ }
+}
+command staff {
+ [empty] {
+ help Shows all online staff.;
+ run staff;
+ }
+}
+command console_join {
+ [string:name] {
+ run console_join name;
+ type console;
+ }
+}
+command console_leave {
+ [string:name] {
+ run console_leave name;
+ type console;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/list/List.java b/src/main/java/com/redstoner/modules/list/List.java
new file mode 100644
index 0000000..d5a0016
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/list/List.java
@@ -0,0 +1,194 @@
+package com.redstoner.modules.list;
+
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+import net.nemez.chatapi.click.Message;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 5, compatible = 4)
+public class List implements Module
+{
+ private HashMap<String, Integer> onConsole;
+
+ @Override
+ public void postEnable()
+ {
+ onConsole = new HashMap<>();
+ }
+
+ @Command(hook = "console_join")
+ public boolean console_join(CommandSender sender, String name)
+ {
+ if (onConsole.containsKey(name))
+ onConsole.put(name, onConsole.get(name) + 1);
+ else
+ onConsole.put(name, 1);
+ return true;
+ }
+
+ @Command(hook = "console_leave")
+ public boolean console_leave(CommandSender sender, String name)
+ {
+ if (onConsole.containsKey(name))
+ if (onConsole.get(name) == 1)
+ onConsole.remove(name);
+ else
+ onConsole.put(name, onConsole.get(name) - 1);
+ return true;
+ }
+
+ @Command(hook = "staff")
+ public boolean staff(CommandSender sender)
+ {
+ return listRank(sender, "staff");
+ }
+
+ @Command(hook = "list")
+ public boolean list(CommandSender sender)
+ {
+ return (listRank(sender, "all"));
+ }
+
+ @Command(hook = "list_rank")
+ public boolean listRank(CommandSender sender, String rank)
+ {
+ int onlinePlayers = Bukkit.getOnlinePlayers().size();
+ getLogger().message(sender, "", "&7There are &e" + onlinePlayers + "&7 out of maximum &e"
+ + Bukkit.getMaxPlayers() + "&7 players online.");
+
+ rank = rank.toLowerCase();
+ boolean all = rank.equals("all");
+
+ if (onlinePlayers == 0 && !rank.contains("console") && !all)
+ return true;
+
+ rank = rank.replace("staff", "mit mod admin lead");
+
+ boolean shownAnything = false;
+
+ if (rank.contains("visitor") || all)
+ shownAnything |= show(sender, "&7Visitors", getPlayers(sender, "group.visitor", "group.member"), all);
+ if (rank.contains("member") || all)
+ shownAnything |= show(sender, "&fMembers", getPlayers(sender, "group.member", "group.builder"), all);
+ if (rank.contains("builder") || all)
+ shownAnything |= show(sender, "&aBuilders", getPlayers(sender, "group.builder", "group.trusted"), all);
+ if (rank.contains("trusted") || all)
+ shownAnything |= show(sender, "&3Trusteds", getPlayers(sender, "group.trusted", "group.trainingmod"), all);
+ if (rank.contains("trainingmod") || rank.contains("mit") || all)
+ shownAnything |= show(sender, "&cTrainingmod &e•", getPlayers(sender, "group.trainingmod", "group.mod"),
+ all);
+ if (rank.contains("mod") || all)
+ shownAnything |= show(sender, "&cModerators", getPlayers(sender, "group.mod", "group.admin"), all);
+ if (rank.contains("admin") || all)
+ shownAnything |= show(sender, "&4Admins", getPlayers(sender, "group.admin", null), all);
+ if (rank.contains("lead") || all)
+ shownAnything |= show(sender, "&4Leads •", getPlayers(sender, "group.lead", null), all);
+ if (rank.contains("console") || all)
+ {
+ if (sender.hasPermission("utils.list.console"))
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Entry<String, Integer> entry : onConsole.entrySet())
+ {
+ if (entry.getValue() > 0)
+ {
+ sb.append(entry.getKey());
+ sb.append("&7, ");
+ }
+ }
+ String players = sb.toString().replaceAll(", $", "");
+ shownAnything |= show(sender, "&9Console" + afk(Bukkit.getConsoleSender()), players);
+ }
+ else
+ {
+ if (!all)
+ {
+ getLogger().message(sender, true, "You do not have permissions to see who's on console!");
+ shownAnything = true;
+ }
+ }
+ }
+ if (!shownAnything)
+ {
+ getLogger().message(sender, new String[] {
+ "Looks like I couldn't figure out what you meant. Try again with different parameters maybe?",
+ "Possible parameters are: &eAll&7, &eStaff&7, &eVisitor&7, &eMember&7, &eBuilder&7, &eTrusted&7, &eMit&7, &eMod&7, &eAdmin&7 and &eLead",
+ "You can also combine any of the parameters, like this: &eMember, Staff"});
+ }
+ return true;
+ }
+
+ public boolean show(CommandSender sender, String rank, String players)
+ {
+ return show(sender, rank, players, false);
+ }
+
+ public boolean show(CommandSender sender, String rank, String players, boolean all)
+ {
+ if (players.length() == 0)
+ {
+ if (!all)
+ {
+ players = "None";
+ }
+ else
+ players = null;
+ }
+ if (players != null)
+ {
+ Message m = new Message(sender, null);
+ m.appendText("&8[" + rank + "&8]&7: " + players);
+ m.send();
+ return true;
+ }
+ return false;
+ }
+
+ public String getPlayers(CommandSender sender, String positive, String negative)
+ {
+ Player player = null;
+ if (sender instanceof Player)
+ player = (Player) sender;
+ StringBuilder sb = new StringBuilder();
+ for (Player p : Bukkit.getOnlinePlayers())
+ {
+ if (p.hasPermission(positive) && (negative == null || !p.hasPermission(negative))
+ && (positive.equals("group.lead") || !p.hasPermission("group.lead")))
+ {
+ if (player == null || player.canSee(p))
+ {
+ sb.append(Utils.getName(p) + afk(p) + vanish(p));
+ sb.append(", ");
+ }
+ }
+ }
+ return sb.toString().replaceAll(", $", "");
+ }
+
+ public String afk(CommandSender sender)
+ {
+ return DataManager.getState(sender, "afk")
+ ? (String) DataManager.getConfigOrDefault("afk", "indicator", "&7[AFK]")
+ : "";
+ }
+
+ public String vanish(Player player)
+ {
+ return DataManager.getState(player, "vanished")
+ ? (String) DataManager.getConfigOrDefault("vanish", "indicator", "&7[V]")
+ : "";
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/CancelledEventsHandler.java b/src/main/java/com/redstoner/modules/loginsecurity/CancelledEventsHandler.java
new file mode 100644
index 0000000..e39d781
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/CancelledEventsHandler.java
@@ -0,0 +1,95 @@
+package com.redstoner.modules.loginsecurity;
+
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.event.player.PlayerDropItemEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerItemHeldEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.event.player.PlayerPickupArrowEvent;
+import org.bukkit.event.player.PlayerPickupItemEvent;
+
+public class CancelledEventsHandler implements Listener {
+ private LoginSecurity mainClass;
+
+ public CancelledEventsHandler(LoginSecurity mainClass) {
+ this.mainClass = mainClass;
+ }
+
+ @EventHandler
+ public void onMove(PlayerMoveEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.getPlayer().teleport(LoginSecurity.loggingIn.get(e.getPlayer().getUniqueId()));
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onChat(AsyncPlayerChatEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.getPlayer().sendMessage(ChatColor.RED + "You must login before you can chat!");
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onCommand(PlayerCommandPreprocessEvent e) {
+ String command = e.getMessage();
+
+ if (!command.startsWith("/login") && isLoggingIn(e.getPlayer())) {
+ e.getPlayer().sendMessage(ChatColor.RED + "You must login before you can execute commands!");
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onItemHold(PlayerItemHeldEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onItemPickup(PlayerPickupItemEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onItemDrop(PlayerDropItemEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onInteract(PlayerInteractEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onArrowPickup(PlayerPickupArrowEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onInvClick(InventoryClickEvent e) {
+ if (e.getWhoClicked() instanceof Player && isLoggingIn((Player) e.getWhoClicked())) {
+ e.setCancelled(true);
+ }
+ }
+
+ private boolean isLoggingIn(Player player) {
+ return mainClass.isLoggingIn(player);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/CryptographyHandler.java b/src/main/java/com/redstoner/modules/loginsecurity/CryptographyHandler.java
new file mode 100644
index 0000000..48e81a9
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/CryptographyHandler.java
@@ -0,0 +1,53 @@
+package com.redstoner.modules.loginsecurity;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Base64;
+
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
+public class CryptographyHandler {
+ public static String hash(String password, String salt) {
+ String algorithm = "PBKDF2WithHmacSHA256";
+ int derivedKeyLength = 256;
+ int iterations = 200000;
+ byte[] decodedSalt = Base64.getDecoder().decode(salt.getBytes());
+
+ KeySpec spec = new PBEKeySpec(password.toCharArray(), decodedSalt, iterations, derivedKeyLength);
+
+ byte[] hashed = null;
+
+ try {
+ SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
+
+ hashed = f.generateSecret(spec).getEncoded();
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+
+ return Base64.getEncoder().encodeToString(hashed).substring(0, 43);
+ }
+
+ public static boolean verify(String password, String salt, String hash) {
+ return hash(password, salt).equals(hash);
+ }
+
+ public static boolean verify(String password, String stored) {
+ String[] split = stored.split("\\$");
+
+ return verify(password, split[3], split[4]);
+ }
+
+ public static String generateSalt() throws NoSuchAlgorithmException, NoSuchProviderException {
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+
+ byte[] salt = new byte[16];
+ random.nextBytes(salt);
+
+ return Base64.getEncoder().encodeToString(salt).substring(0, 22);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.cmd b/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.cmd
new file mode 100644
index 0000000..952b3ed
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.cmd
@@ -0,0 +1,49 @@
+command register {
+ perm utils.loginsecurity;
+
+ [string:password] {
+ run register password;
+ help Protects your account with a password;
+ type player;
+ }
+}
+
+command login {
+ perm utils.loginsecurity;
+
+ [string:password] {
+ run login password;
+ help Logs you in;
+ type player;
+ }
+}
+
+command cgpass {
+ perm utils.loginsecurity;
+
+ [string:oldPassword] [string:newPassword] {
+ run cgpass oldPassword newPassword;
+ help Changes your password to the specified one;
+ type player;
+ }
+}
+
+command rmpass {
+ perm utils.loginsecurity;
+
+ [string:oldPassword] {
+ run rmpass oldPassword;
+ help Removes the password of your account;
+ type player;
+ }
+}
+
+command rmotherpass {
+ perm utils.loginsecurity.admin;
+
+ [string:playerName] {
+ run rmotherpass playerName;
+ help removes the password of another player;
+ perm utils.loginsecurity.admin;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.java b/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.java
new file mode 100644
index 0000000..7bcb89a
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.java
@@ -0,0 +1,263 @@
+package com.redstoner.modules.loginsecurity;
+
+import java.io.Serializable;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.scheduler.BukkitScheduler;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.mysql.JSONManager;
+import com.redstoner.misc.mysql.MysqlHandler;
+import com.redstoner.misc.mysql.elements.ConstraintOperator;
+import com.redstoner.misc.mysql.elements.MysqlConstraint;
+import com.redstoner.misc.mysql.elements.MysqlDatabase;
+import com.redstoner.misc.mysql.elements.MysqlField;
+import com.redstoner.misc.mysql.elements.MysqlTable;
+import com.redstoner.misc.mysql.types.text.VarChar;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class LoginSecurity implements Module, Listener
+{
+ protected static Map<UUID, Location> loggingIn;
+ private MysqlTable table;
+
+ @Override
+ public boolean onEnable()
+ {
+ Map<Serializable, Serializable> config = JSONManager.getConfiguration("loginsecurity.json");
+ if (config == null || !config.containsKey("database") || !config.containsKey("table"))
+ {
+ getLogger().message(Bukkit.getConsoleSender(), true,
+ "Could not load the LoginSecurity config file, disabling!");
+ return false;
+ }
+ try
+ {
+ MysqlDatabase database = MysqlHandler.INSTANCE.getDatabase((String) config.get("database"));
+ MysqlField uuid = new MysqlField("uuid", new VarChar(36), true);
+ MysqlField pass = new MysqlField("pass", new VarChar(88), true);
+ database.createTableIfNotExists((String) config.get("table"), uuid, pass);
+ table = database.getTable((String) config.get("table"));
+ }
+ catch (NullPointerException e)
+ {
+ getLogger().message(Bukkit.getConsoleSender(), true, "Could not use the LoginSecurity config, disabling!");
+ return false;
+ }
+ loggingIn = new HashMap<>();
+ Bukkit.getServer().getPluginManager().registerEvents(new CancelledEventsHandler(this), Main.plugin);
+ return true;
+ }
+
+ public static Map<UUID, Location> getLoggingIn()
+ {
+ return loggingIn;
+ }
+
+ @Command(hook = "register")
+ public void register(CommandSender sender, String password)
+ {
+ Player player = (Player) sender;
+ if (isRegistered(player))
+ {
+ player.sendMessage(ChatColor.GREEN + "You are already registered!");
+ return;
+ }
+ try
+ {
+ if (registerPlayer(player, password))
+ {
+ player.sendMessage(ChatColor.GREEN + "Succesfully registered!");
+ return;
+ }
+ }
+ catch (NoSuchAlgorithmException | NoSuchProviderException e)
+ {
+ e.printStackTrace();
+ }
+ player.sendMessage(ChatColor.RED + "Failed to register, please contact an admin!");
+ }
+
+ @Command(hook = "login")
+ public void login(CommandSender sender, String password)
+ {
+ Player player = (Player) sender;
+ if (!isRegistered(player))
+ {
+ player.sendMessage(ChatColor.RED + "You are not registered!");
+ return;
+ }
+ if (CryptographyHandler.verify(password, getHash(player)))
+ {
+ loggingIn.remove(player.getUniqueId());
+ }
+ else
+ {
+ player.sendMessage(ChatColor.RED + "Wrong password!");
+ }
+ }
+
+ @Command(hook = "cgpass")
+ public void cgpass(CommandSender sender, String oldPassword, String newPassword)
+ {
+ Player player = (Player) sender;
+ if (!isRegistered(player))
+ {
+ player.sendMessage(ChatColor.RED + "You are not registered!");
+ return;
+ }
+ if (!CryptographyHandler.verify(oldPassword, getHash(player)))
+ {
+ player.sendMessage(ChatColor.RED + "The old password you entered is wrong!");
+ return;
+ }
+ if (oldPassword.equals(newPassword))
+ {
+ player.sendMessage(ChatColor.RED + "You entered the same password!");
+ return;
+ }
+ if (table.delete(getUuidConstraint(player)))
+ {
+ try
+ {
+ registerPlayer(player, newPassword);
+ player.sendMessage(ChatColor.GREEN + "Succesfully changed password!");
+ }
+ catch (NoSuchAlgorithmException | NoSuchProviderException e)
+ {
+ e.printStackTrace();
+ player.sendMessage(ChatColor.RED + "Failed to set new password!");
+ }
+ }
+ else
+ {
+ player.sendMessage(ChatColor.RED + "Failed to remove old password from database!");
+ }
+ }
+
+ @Command(hook = "rmpass")
+ public void rmpass(CommandSender sender, String oldPassword)
+ {
+ Player player = (Player) sender;
+ if (!isRegistered(player))
+ {
+ player.sendMessage(ChatColor.RED + "You are not registered!");
+ return;
+ }
+ if (!CryptographyHandler.verify(oldPassword, getHash(player)))
+ {
+ player.sendMessage(ChatColor.RED + "The old password you entered is wrong!");
+ return;
+ }
+ if (table.delete(getUuidConstraint(player)))
+ {
+ player.sendMessage(ChatColor.GREEN + "Succesfully removed password!");
+ }
+ else
+ {
+ player.sendMessage(ChatColor.RED + "Failed to remove old password from database!");
+ }
+ }
+
+ @Command(hook = "rmotherpass")
+ public void rmotherpass(CommandSender sender, String playerName)
+ {
+ if (playerName.equals(""))
+ {
+ sender.sendMessage(ChatColor.RED + "That's not a valid player!");
+ return;
+ }
+ @SuppressWarnings("deprecation")
+ OfflinePlayer player = Bukkit.getOfflinePlayer(playerName);
+ if (!isRegistered(player))
+ {
+ sender.sendMessage(ChatColor.RED + "That player is not registered!");
+ return;
+ }
+ if (table.delete(getUuidConstraint(player)))
+ {
+ sender.sendMessage(ChatColor.GREEN + "Successfully removed " + playerName + "'s password!");
+ }
+ else
+ {
+ sender.sendMessage(ChatColor.RED + "Failed to remove " + playerName + "'s password!");
+ }
+ }
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent e)
+ {
+ Player player = e.getPlayer();
+ if (!isRegistered(player))
+ {
+ return;
+ }
+ getLogger().message(player, "You'll have to log in within 60s or you'll be kicked!");
+ loggingIn.put(player.getUniqueId(), player.getLocation());
+ BukkitScheduler scheduler = Bukkit.getScheduler();
+ RepeatingLoginRunnable repeatingRunnable = new RepeatingLoginRunnable(this, player);
+ repeatingRunnable.setId(scheduler.scheduleSyncRepeatingTask(Main.plugin, repeatingRunnable, 0L, 2L));
+ scheduler.scheduleSyncDelayedTask(Main.plugin, new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if (isLoggingIn(player))
+ {
+ scheduler.cancelTask(repeatingRunnable.getId());
+ player.kickPlayer("You didn't login in time!");
+ }
+ }
+ }, 1200L);
+ }
+
+ public boolean isLoggingIn(Player player)
+ {
+ return loggingIn.containsKey(player.getUniqueId());
+ }
+
+ public MysqlConstraint getUuidConstraint(OfflinePlayer player)
+ {
+ return new MysqlConstraint("uuid", ConstraintOperator.EQUAL, player.getUniqueId().toString());
+ }
+
+ public boolean isRegistered(OfflinePlayer player)
+ {
+ return table.get("uuid", getUuidConstraint(player)).length > 0;
+ }
+
+ public String getHash(OfflinePlayer player)
+ {
+ return (String) table.get("pass", getUuidConstraint(player))[0];
+ }
+
+ public boolean registerPlayer(Player player, String password)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ String salt = CryptographyHandler.generateSalt();
+ String hash = CryptographyHandler.hash(password, salt);
+ String toInsert = "$pbkdf2-sha256$200000$" + salt + "$" + hash;
+ return table.insert(player.getUniqueId().toString(), toInsert);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/RepeatingLoginRunnable.java b/src/main/java/com/redstoner/modules/loginsecurity/RepeatingLoginRunnable.java
new file mode 100644
index 0000000..4e8db6d
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/RepeatingLoginRunnable.java
@@ -0,0 +1,37 @@
+package com.redstoner.modules.loginsecurity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+public class RepeatingLoginRunnable implements Runnable {
+ private int id = -1;
+ private Player player;
+ private LoginSecurity mainClass;
+
+ public RepeatingLoginRunnable(LoginSecurity mainClass, Player player) {
+ this.player = player;
+ this.mainClass = mainClass;
+ }
+
+ @Override
+ public void run() {
+ if (!player.isOnline()) {
+ LoginSecurity.loggingIn.remove(player.getUniqueId());
+ Bukkit.getScheduler().cancelTask(id);
+ }
+
+ if (!mainClass.isLoggingIn(player)) {
+ player.sendMessage(ChatColor.GREEN + "Successfully logged in!");
+ Bukkit.getScheduler().cancelTask(id);
+ }
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/logs/LogEntry.java b/src/main/java/com/redstoner/modules/logs/LogEntry.java
new file mode 100644
index 0000000..3ccc844
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/logs/LogEntry.java
@@ -0,0 +1,71 @@
+package com.redstoner.modules.logs;
+
+public class LogEntry
+{
+ public final int line;
+ public final int global_line;
+ public final String filename;
+ public final String raw;
+
+ public LogEntry(String raw, int line, int global_line)
+ {
+ this("Unkown", raw, line, global_line);
+ }
+
+ public LogEntry(String filename, String raw, int line, int global_line)
+ {
+ this.raw = resolveColors(raw);
+ this.line = line;
+ this.global_line = global_line;
+ this.filename = filename;
+ }
+
+ public String applyFormat(String format, boolean colors)
+ {
+ // Replace escaped % with placeholder
+ format = format.replace("%%", "§§");
+ // Line numbers
+ format = format.replace("%l", "" + line);
+ format = format.replace("%L", "" + global_line);
+ // Filename
+ format = format.replace("%f", filename);
+ // Strip colors
+ if (!colors)
+ format = format.replace("%r", raw.replaceAll("$.", ""));
+ else
+ format = format.replace("%r", raw);
+ // Convert placeholder back
+ format = format.replace("§§", "%");
+ return format;
+ }
+
+ private String resolveColors(String message)
+ {
+ message = message.replace("", "§0");
+ message = message.replace("", "§1");
+ message = message.replace("", "§2");
+ message = message.replace("", "§3");
+ message = message.replace("", "§4");
+ message = message.replace("", "§5");
+ message = message.replace("", "§6");
+ message = message.replace("", "§7");
+ message = message.replace("", "§8");
+ message = message.replace("", "§9");
+ message = message.replace("", "§a");
+ message = message.replace("", "§b");
+ message = message.replace("", "§c");
+ message = message.replace("", "§d");
+ message = message.replace("", "§e");
+ message = message.replace("", "§f");
+
+ message = message.replace("", "§k");
+ message = message.replace("", "§l");
+ message = message.replace("", "§m");
+ message = message.replace("", "§n");
+ message = message.replace("", "§o");
+
+ message = message.replace("", "§r");
+
+ return message;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/logs/LogHandler.java b/src/main/java/com/redstoner/modules/logs/LogHandler.java
new file mode 100644
index 0000000..76f3849
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/logs/LogHandler.java
@@ -0,0 +1,200 @@
+package com.redstoner.modules.logs;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+import java.util.zip.GZIPInputStream;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.datamanager.DataManager;
+
+public class LogHandler extends Thread
+{
+ private CommandSender sender;
+ private String regex, fileName;
+ private static ArrayList<CommandSender> stillSearching = new ArrayList<>();
+ public int totalFiles = 0;
+ public int filesSearched = 0;
+ public int totalLines = 0;
+ public int currentLine = 0;
+
+ protected LogHandler(CommandSender sender, String regex, String fileName)
+ {
+ this.sender = sender;
+ this.regex = regex;
+ this.fileName = fileName;
+ }
+
+ public void doSearch()
+ {
+ if (stillSearching.contains(sender))
+ {
+ Logs.logger.message(sender, true, "§4 DO NOT EVER TRY TO QUERY TWO SEARCHES AT ONCE. Go die...!");
+ return;
+ }
+ stillSearching.add(sender);
+ this.start();
+ }
+
+ /** Searches the logs for a certain regex and forwards any matches to the sender.
+ *
+ * @param sender the issuer of the search
+ * @param regex the regex to search for. Will be wrapped in "^.*" and ".*$" if it is missing line delimiters
+ * @param fileName the name of the files to search through. May contain wildcards. */
+ private void search(CommandSender sender, String regex, String fileName)
+ {
+ long starttime = System.currentTimeMillis();
+ int matches = 0;
+ Logs.logger.message(sender, "Starting log search for &e" + regex + "&7 in &e" + fileName
+ + " &7now. &cPlease do not query any other searches until this one completes.");
+ try
+ {
+ if (!regex.startsWith("^"))
+ regex = "^.*" + regex;
+ if (!regex.endsWith("$"))
+ regex += ".*$";
+ File logFolder = Logs.getLogsDir();
+ Pattern fileNamePattern;
+ try
+ {
+ fileNamePattern = Pattern.compile(fileName);
+ }
+ catch (PatternSyntaxException e)
+ {
+ Logs.logger.message(sender, true, "An error occured trying to compile the filename pattern!");
+ stillSearching.remove(sender);
+ return;
+ }
+ File[] files = logFolder.listFiles(new FilenameFilter()
+ {
+ @Override
+ public boolean accept(File dir, String name)
+ {
+ return fileNamePattern.matcher(name).matches();
+ }
+ });
+ totalFiles = files.length;
+ if (totalFiles == 0)
+ {
+ Logs.logger.message(sender, true, "No files found!");
+ stillSearching.remove(sender);
+ return;
+ }
+ else
+ Logs.logger.message(sender, "A total of &e" + totalFiles + "&7 files will be searched!");
+
+ boolean progress = (boolean) DataManager.getOrDefault(Utils.getID(sender), "Logs", "progress", true);
+ Pattern searchPattern;
+ try
+ {
+ searchPattern = Pattern.compile(regex);
+ }
+ catch (PatternSyntaxException e)
+ {
+ Logs.logger.message(sender, true, "An error occured trying to compile the search pattern!");
+ stillSearching.remove(sender);
+ return;
+ }
+ for (File file : files)
+ {
+ if (file.getName().endsWith(".gz"))
+ {
+
+ BufferedReader inputReader = new BufferedReader(
+ new InputStreamReader(new GZIPInputStream(new FileInputStream(file))));
+ matches += searchStream(inputReader, searchPattern, sender, file.getName());
+ inputReader.close();
+ }
+ else
+ {
+ BufferedReader inputReader = new BufferedReader(new FileReader(file));
+ matches += searchStream(inputReader, searchPattern, sender, file.getName());
+ inputReader.close();
+ }
+ filesSearched++;
+ if (progress)
+ {
+ sender.sendMessage("§7So far, §e" + filesSearched + "§7/§e" + totalFiles + "§7 File(s) and §e"
+ + totalLines + "§7 Line(s) were searched.");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Logs.logger.message(sender, true,
+ "An unexpected error occured, please check your search parameters and try again!");
+ stillSearching.remove(sender);
+ return;
+ }
+ stillSearching.remove(sender);
+ if ((boolean) DataManager.getOrDefault(Utils.getID(sender), "Logs", "summary", true))
+ {
+ String[] message = new String[2];
+ message[0] = "§aYour search completed after " + (System.currentTimeMillis() - starttime) + "ms!";
+ message[1] = "§7In total: §e" + filesSearched + "§7 File(s) and §e" + totalLines
+ + "§7 Line(s) were searched, §a" + matches + "§7 Match(es) were found!";
+ Logs.logger.message(sender, message);
+ }
+ return;
+ }
+
+ /** This function searches through an InputStream to find a regex. If it finds a match, it will forward that match to the sender and increase the match counter.
+ *
+ * @param inputReader the input reader containing the data
+ * @param regex the regex to search for
+ * @param sender the issuer of the search
+ * @param singleFile true if only a single file is being searched, false if the original filename contained wildcards.
+ * @param filename the name of the file that is currently being searched
+ * @return how many matches it found
+ * @throws IOException if something goes wrong */
+ private int searchStream(BufferedReader inputReader, Pattern searchPattern, CommandSender sender, String filename)
+ throws IOException
+ {
+ String format = (String) DataManager.getOrDefault(Utils.getID(sender), "Logs", "format", Logs.defaultFormat);
+ boolean colors = (boolean) DataManager.getOrDefault(Utils.getID(sender), "Logs", "colors", true);
+ Player p = null;
+ if (sender instanceof Player)
+ p = (Player) sender;
+ int matches = 0;
+ String line = "";
+ currentLine = 0;
+ while ((line = inputReader.readLine()) != null)
+ {
+ totalLines++;
+ currentLine++;
+ if (searchPattern.matcher(line).matches())
+ {
+ if (((p != null) && (!p.isOnline())))
+ {
+ stillSearching.remove(sender);
+ throw new IOException("The player has left during the search. Aborting now.");
+ }
+ LogEntry entry = new LogEntry(filename, line, currentLine, totalLines);
+ sender.sendMessage(entry.applyFormat(format, colors));
+ matches++;
+ }
+ }
+ return matches;
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ search(sender, regex, fileName);
+ }
+ catch (Exception e)
+ {}
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/logs/Logs.cmd b/src/main/java/com/redstoner/modules/logs/Logs.cmd
new file mode 100644
index 0000000..c5283fe
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/logs/Logs.cmd
@@ -0,0 +1,34 @@
+command log {
+ perm utils.logs;
+ alias logs;
+ search [string:file(s)] [string:search...] {
+ run search_logs file(s) search;
+ help Performs the specified search operation on the logs. Wildcards are supported in filenames. Search string is a regex.;
+ type player;
+ }
+ format {
+ run show_format;
+ help Displays your current log output format with an example result.;
+ type player;
+ }
+ format_help {
+ run show_format_help;
+ help Displays all available placeholders for the formatting;
+ type player;
+ }
+ option_help {
+ run show_option_help;
+ help Displays all available options.;
+ type player;
+ }
+ set format [string:format] {
+ run set_format format;
+ help Sets a new log output format;
+ type player;
+ }
+ set [string:option] [boolean:state] {
+ run set_option option state;
+ help Allows you to enable or disable various features such as sumamries, live progress updates, etc...;
+ type player;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/logs/Logs.java b/src/main/java/com/redstoner/modules/logs/Logs.java
new file mode 100644
index 0000000..b54bfc9
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/logs/Logs.java
@@ -0,0 +1,157 @@
+package com.redstoner.modules.logs;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.command.CommandSender;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.ModuleLogger;
+import com.redstoner.modules.datamanager.DataManager;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 4, compatible = 4)
+public class Logs implements Module
+{
+ public static final String defaultFormat = "§7 > %f: %r";
+ private final LogEntry example_1 = new LogEntry("1970-01-01-2.log.gz",
+ "[01:23:45] [Async Chat Thread - #1337/INFO]: §aFooBar §7→ §4THIS SERVER SUCKS", 14, 73);
+ private final LogEntry example_2 = new LogEntry("1970-01-01-2.log.gz",
+ "[01:23:45] [Server thread/INFO]: admin issued server command: /ban FooBar Ab00se", 15, 74);
+ protected static ModuleLogger logger;
+
+ @Override
+ public void firstLoad()
+ {
+ Module.super.firstLoad();
+ DataManager.setConfig("logs.root", "/etc/minecraft/redstoner/logs");
+ }
+
+ @Override
+ public boolean onEnable()
+ {
+ Module.super.onEnable();
+ logger = getLogger();
+ return true;
+ }
+
+ public static File getLogsDir()
+ {
+ return new File((String) DataManager.getConfigOrDefault("logs.root", "../logs"));
+ }
+
+ @Command(hook = "search_logs")
+ public boolean search_logs(CommandSender sender, String files, String search)
+ {
+ LogHandler handler = new LogHandler(sender, search, files);
+ handler.doSearch();
+ return true;
+ }
+
+ // FORMATTING
+ @Command(hook = "show_format")
+ public boolean show_format(CommandSender sender)
+ {
+ showExample(sender);
+ return true;
+ }
+
+ @Command(hook = "set_format")
+ public boolean set_format(CommandSender sender, String format)
+ {
+ if (format.equals("--reset"))
+ format = defaultFormat;
+ format = format.replace("&", "§").replace("$$", "&");
+ DataManager.setData(sender, "format", format);
+ showExample(sender, format);
+ return true;
+ }
+
+ private void showExample(CommandSender sender)
+ {
+ showExample(sender, (String) DataManager.getOrDefault(sender, "format", defaultFormat));
+ }
+
+ private void showExample(CommandSender sender, String format)
+ {
+ sender.sendMessage(getLogger().getHeader());
+ sender.sendMessage("Your format is: " + format);
+ sender.sendMessage("Here's an example of what it would look like in an actual log search:");
+ boolean colors = (boolean) DataManager.getOrDefault(sender, "colors", true);
+ if ((boolean) DataManager.getOrDefault(sender, "progress", true))
+ {
+ sender.sendMessage("§7So far, §e1§7/§e2§7 File(s) and §e68§7 Line(s) were searched.");
+ }
+ sender.sendMessage(example_1.applyFormat(format, colors));
+ sender.sendMessage(example_2.applyFormat(format, colors));
+ if ((boolean) DataManager.getOrDefault(sender, "summary", true))
+ {
+ sender.sendMessage("§aSearch completed after 39ms!");
+ sender.sendMessage(
+ "§7In total: §e2§7 File(s) and §e105§7 Line(s) were searched, §a2§7 Match(es) were found!");
+ }
+ }
+
+ @Command(hook = "show_format_help")
+ public boolean format_help(CommandSender sender)
+ {
+ //@noformat
+ String[] format_help = new String[] {
+ " &e%l&cine&7 -> Linenumber in the current file",
+ " &e%L&cine&7 -> Global linenumber (sum of all previous files + current line)",
+ " &e%f&cile&7 -> Complete filename",
+ " &e%r&caw&7 -> The raw line containing the text as it appears in the logs",
+ "",
+ " &7Use %% to gain a literal %."};
+ //@format
+ getLogger().message(sender, format_help);
+ return true;
+ }
+
+ // SEARCH OPTIONS
+ @Command(hook = "show_option_help")
+ public boolean show_options(CommandSender sender)
+ {
+ List<String> options = new ArrayList<>(Option.values().length + 1);
+ options.add("Available options are:");
+ for (Option o : Option.values())
+ options.add(" - " + o.toString());
+ getLogger().message(sender, options.toArray(new String[] {}));
+ return true;
+ }
+
+ @Command(hook = "set_option")
+ public boolean set_option(CommandSender sender, String option, boolean state)
+ {
+ option = option.toLowerCase();
+ Option o = null;
+ try
+ {
+ o = Option.valueOf(option);
+ }
+ catch (IllegalArgumentException e)
+ {}
+ if (o == null)
+ {
+ getLogger().message(sender, true,
+ "Invalid option! To get a list of all available options, run &e/logs option_help");
+ return true;
+ }
+ DataManager.setData(sender, option, state);
+ getLogger().message(sender,
+ "Successfully turned displaying of &e" + option + (state ? " &aon&7!" : " &coff&7!"));
+ return true;
+ }
+}
+
+enum Option
+{
+ summary,
+ progress,
+ colors
+}
diff --git a/src/main/java/com/redstoner/modules/mentio/Mentio.cmd b/src/main/java/com/redstoner/modules/mentio/Mentio.cmd
new file mode 100644
index 0000000..230adf8
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/mentio/Mentio.cmd
@@ -0,0 +1,16 @@
+command mentio {
+ add [string:trigger] {
+ help Triggers you when the trigger gets said.;
+ run addmentio trigger;
+ }
+ delete [string:trigger] {
+ help Deletes a mentio.;
+ run delmentio trigger;
+ }
+ list {
+ help Lists your mentios.;
+ run listmentios;
+ }
+ perm utils.mentio;
+ type player;
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/mentio/Mentio.java b/src/main/java/com/redstoner/modules/mentio/Mentio.java
new file mode 100644
index 0000000..3db8edf
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/mentio/Mentio.java
@@ -0,0 +1,180 @@
+package com.redstoner.modules.mentio;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.UUID;
+import java.util.regex.Pattern;
+
+import org.bukkit.Sound;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.ignore.Ignore;
+
+import net.nemez.chatapi.click.Message;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Mentio implements Module, Listener
+{
+ private File mentioLocation = new File(Main.plugin.getDataFolder(), "mentio.json");
+ private JSONObject mentios;
+
+ @Override
+ public boolean onEnable()
+ {
+ loadMentios();
+ return true;
+ }
+
+ @Override
+ public void onDisable()
+ {
+ saveMentios();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "addmentio")
+ public boolean addMentio(CommandSender sender, String trigger)
+ {
+ Player player = (Player) sender;
+ UUID uuid = player.getUniqueId();
+ JSONArray playerMentios = (JSONArray) mentios.get(uuid.toString());
+ if (playerMentios == null)
+ {
+ playerMentios = new JSONArray();
+ playerMentios.add(player.getName());
+ playerMentios.add(player.getDisplayName().split(" ")[0].replaceAll("§[0-9a-fk-o]", ""));
+ }
+ if (playerMentios.contains(trigger))
+ getLogger().message(sender, true, "You already had that as a mentio!");
+ else
+ {
+ playerMentios.add(trigger);
+ getLogger().message(sender, "Successfully added the trigger §e" + trigger + " §7for you!");
+ mentios.put(uuid.toString(), playerMentios);
+ saveMentios();
+ }
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "delmentio")
+ public boolean delMentio(CommandSender sender, String trigger)
+ {
+ Player player = (Player) sender;
+ UUID uuid = player.getUniqueId();
+ JSONArray playerMentios = (JSONArray) mentios.get(uuid.toString());
+ if (playerMentios == null)
+ {
+ playerMentios = new JSONArray();
+ playerMentios.add(player.getName());
+ playerMentios.add(player.getDisplayName().split(" ")[0].replaceAll("§[0-9a-fk-o]", ""));
+ }
+ if (!playerMentios.remove(trigger))
+ getLogger().message(sender, true, "You didn't have that as a mentio!");
+ else
+ {
+ getLogger().message(sender, "Successfully removed the trigger §e" + trigger + " §7for you!");
+ mentios.put(uuid.toString(), playerMentios);
+ saveMentios();
+ }
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "listmentios")
+ public boolean listMentios(CommandSender sender)
+ {
+ ArrayList<String> message = new ArrayList<>();
+ Player player = (Player) sender;
+ UUID uuid = player.getUniqueId();
+ JSONArray playerMentios = (JSONArray) mentios.get(uuid.toString());
+ if (playerMentios == null)
+ {
+ playerMentios = new JSONArray();
+ playerMentios.add(player.getName());
+ playerMentios.add(player.getDisplayName().split(" ")[0].replaceAll("§[0-9a-fk-or]", ""));
+ }
+ for (Object raw : playerMentios)
+ {
+ String mentio = (String) raw;
+ message.add("&2 -> &e" + mentio);
+ }
+ getLogger().message(sender, message.toArray(new String[] {}));
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onPlayerChat(AsyncPlayerChatEvent event)
+ {
+ if (event.isCancelled())
+ return;
+ for (Player player : event.getRecipients())
+ {
+ if (ModuleLoader.exists("Ignore") ? !Ignore.getIgnoredBy(event.getPlayer()).sendTo(player) : false)
+ return;
+ UUID uuid = player.getUniqueId();
+ JSONArray playerMentios = (JSONArray) mentios.get(uuid.toString());
+ if (playerMentios == null)
+ {
+ playerMentios = new JSONArray();
+ playerMentios.add(player.getName());
+ playerMentios.add(player.getDisplayName().split(" ")[0].replaceAll("§[0-9a-fk-o]", ""));
+ }
+ for (Object raw : playerMentios)
+ {
+ String mentio = (String) raw;
+ if (event.getMessage().toLowerCase().contains(mentio.toLowerCase()))
+ {
+ event.getRecipients().remove(player);
+ String temp = event.getMessage().replaceAll("(?i)" + Pattern.quote(mentio) + ".*", "");
+ String lastColorCodes = "§r";
+ char lastChar = ' ';
+ for (char c : temp.toCharArray())
+ {
+ if (lastChar == '§')
+ lastColorCodes += "§" + c;
+ lastChar = c;
+ }
+ Message m = new Message(player, event.getPlayer());
+ m.appendText(event.getFormat().replace("%1$s", event.getPlayer().getDisplayName()).replace("%2$s",
+ event.getMessage().replaceFirst("(?i)(" + Pattern.quote(mentio) + ")([^ ]*)",
+ "§a§o$1$2" + lastColorCodes)));
+ m.send();
+ player.playSound(player.getLocation(), Sound.ENTITY_CHICKEN_EGG, 1, 1);
+ return;
+ }
+ }
+ }
+ }
+
+ private void loadMentios()
+ {
+ mentios = JsonManager.getObject(mentioLocation);
+ if (mentios == null)
+ mentios = new JSONObject();
+ }
+
+ private void saveMentios()
+ {
+ JsonManager.save(mentios, mentioLocation);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/message/Message.cmd b/src/main/java/com/redstoner/modules/message/Message.cmd
new file mode 100644
index 0000000..382e52e
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/message/Message.cmd
@@ -0,0 +1,43 @@
+command message {
+ alias m;
+ alias em;
+ alias msg;
+ alias emsg;
+ alias t;
+ alias et;
+ alias tell;
+ alias etell;
+ alias w;
+ alias ew;
+ alias whisper;
+ alias ewhisper;
+ [string:player] [string:message...] {
+ run message player message;
+ help Sends a direct message to a player.;
+ perm utils.message;
+ }
+}
+
+command reply {
+ alias r;
+ alias er;
+ alias ereply;
+ [string:message...] {
+ run reply message;
+ help Sends a direct message to the last person you talked to.;
+ perm utils.message;
+ }
+}
+
+command pmtoggle {
+ [empty] {
+ help Turns off your toggle.;
+ type player;
+ run pmtoggle_off;
+ }
+ [string:player] {
+ help Turns on your pmtoggle and locks onto <player>.;
+ type player;
+ run pmtoggle player;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/message/Message.java b/src/main/java/com/redstoner/modules/message/Message.java
new file mode 100644
index 0000000..8c9f95d
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/message/Message.java
@@ -0,0 +1,226 @@
+package com.redstoner.modules.message;
+
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.Command.AsyncType;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.BroadcastFilter;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+import com.redstoner.modules.ignore.Ignore;
+import com.redstoner.modules.socialspy.Socialspy;
+
+import net.nemez.chatapi.ChatAPI;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 4, compatible = 4)
+public class Message implements Module
+{
+ HashMap<CommandSender, CommandSender> replyTargets = new HashMap<>();
+ HashMap<Player, String> toggles = new HashMap<>();
+
+ @Override
+ public void migrate(Version old)
+ {
+ Module.super.migrate(old);
+ if (old.major() == 4 && old.minor() == 0 && old.revision() <= 3)
+ {
+ DataManager.setConfig("from", getDefaultFormatFrom());
+ DataManager.setConfig("to", getDefaultFormatTo());
+ }
+ }
+
+ @Command(hook = "message", async = AsyncType.ALWAYS)
+ public boolean message(CommandSender sender, String target, String message)
+ {
+ CommandSender p;
+ if (target.equalsIgnoreCase("console"))
+ p = Bukkit.getConsoleSender();
+ else
+ p = Bukkit.getPlayer(target);
+ if (p == null)
+ {
+ getLogger().message(sender, true, "That player couldn't be found!");
+ return true;
+ }
+ else if (ModuleLoader.exists("Ignore") ? !Ignore.getIgnoredBy(sender).sendTo(p) : true)
+ {
+ getLogger().message(sender, true, Utils.getName(p) + " has ignored you. Your message was not sent.");
+ return true;
+ }
+ else
+ {
+ if (ModuleLoader.getModule("Socialspy") != null)
+ Socialspy.spyBroadcast(sender, p, message, "/m", new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return !(recipient.equals(sender) || recipient.equals(p));
+ }
+ });
+
+ String format = (String) DataManager.getConfigOrDefault("to", getDefaultFormatTo());
+ format = ChatAPI.colorify(null, format);
+ format = applyFormat(format, sender, p, message);
+ net.nemez.chatapi.click.Message m = new net.nemez.chatapi.click.Message(sender, null);
+ m.appendText(format);
+ m.send();
+
+ if (!sender.equals(p))
+ {
+ format = (String) DataManager.getConfigOrDefault("from", getDefaultFormatFrom());
+ format = ChatAPI.colorify(null, format);
+ format = applyFormat(format, sender, p, message);
+ net.nemez.chatapi.click.Message m2 = new net.nemez.chatapi.click.Message(p, null);
+ m2.appendText(format);
+ m2.send();
+ }
+ replyTargets.put(sender, p);
+ replyTargets.put(p, sender);
+
+ if (DataManager.getState(p, "afk"))
+ {
+ getLogger().message(sender, "&5That player is currently AFK and may not respond!");
+ }
+ }
+ return true;
+ }
+
+ @Command(hook = "reply", async = AsyncType.ALWAYS)
+ public boolean reply(CommandSender sender, String message)
+ {
+ CommandSender target = replyTargets.get(sender);
+ if (target == null || ((target instanceof OfflinePlayer) && !((OfflinePlayer) target).isOnline()))
+ {
+ getLogger().message(sender, true, "You don't have anyone to reply to!");
+ return true;
+ }
+ else if (ModuleLoader.exists("Ignore") ? !Ignore.getIgnoredBy(sender).sendTo(target) : true)
+ {
+ getLogger().message(sender, true, Utils.getName(target) + " has ignored you. Your message was not sent.");
+ return true;
+ }
+ else
+ {
+ if (ModuleLoader.getModule("Socialspy") != null)
+ Socialspy.spyBroadcast(sender, target, message, "/r", new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return !(recipient.equals(sender) || recipient.equals(target));
+ }
+ });
+
+ String format = (String) DataManager.getConfigOrDefault("to", getDefaultFormatTo());
+ format = ChatAPI.colorify(null, format);
+ format = applyFormat(format, sender, target, message);
+ net.nemez.chatapi.click.Message m = new net.nemez.chatapi.click.Message(sender, null);
+ m.appendText(format);
+ m.send();
+
+ if (!sender.equals(target))
+ {
+ format = (String) DataManager.getConfigOrDefault("from", getDefaultFormatFrom());
+ format = ChatAPI.colorify(null, format);
+ format = applyFormat(format, sender, target, message);
+ net.nemez.chatapi.click.Message m2 = new net.nemez.chatapi.click.Message(target, null);
+ m2.appendText(format);
+ m2.send();
+ }
+ }
+ replyTargets.put(sender, target);
+ replyTargets.put(target, sender);
+ return true;
+ }
+
+ @Command(hook = "pmtoggle_off", async = AsyncType.ALWAYS)
+ public boolean pmtoggle_off(CommandSender sender)
+ {
+ Player player = (Player) sender;
+ if (toggles.remove(player) != null)
+ getLogger().message(player, "Your pmtoggle was removed!");
+ else
+ getLogger().message(player, "You didn't have pmtoggle enabled! Use /pmtoggle <player> to enabled it.");
+ return true;
+ }
+
+ @Command(hook = "pmtoggle", async = AsyncType.ALWAYS)
+ public boolean pmtoggle(CommandSender sender, String player)
+ {
+ Player p = Bukkit.getPlayer(player);
+ if (p == null && !player.equals("CONSOLE"))
+ {
+ getLogger().message(sender, "§cThat player couldn't be found!");
+ return true;
+ }
+ toggles.put((Player) sender, player);
+ getLogger().message(sender, "Locked your pmtoggle onto §6" + player + "§7.");
+ return true;
+ }
+
+ @EventHandler
+ public void onPlayerChat(AsyncPlayerChatEvent event)
+ {
+ Player player = event.getPlayer();
+ if (toggles.containsKey(player))
+ {
+ Bukkit.dispatchCommand(player, "m " + toggles.get(player) + " " + event.getMessage());
+ event.setCancelled(true);
+ }
+ }
+
+ @SuppressWarnings("unlikely-arg-type")
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event)
+ {
+ toggles.remove(event.getPlayer());
+ String player = event.getPlayer().getName();
+ if (toggles.containsValue(player))
+ for (Entry<Player, String> entry : toggles.entrySet())
+ if (entry.getValue().equals(player))
+ {
+ toggles.remove(player);
+ getLogger().message(entry.getKey(),
+ "We removed your pmtoggle for &6" + player + "&7, as they left the game.");
+ }
+ }
+
+ public String applyFormat(String format, CommandSender sender, CommandSender target, String message)
+ {
+ format = format.replace("%%", "§§");
+ format = format.replace("%s", Utils.getName(sender));
+ format = format.replace("%S", sender.getName());
+ format = format.replace("%t", Utils.getName(target));
+ format = format.replace("%T", target.getName());
+ format = format.replace("%m", message);
+ format = format.replaceAll("§§", "%");
+
+ return format;
+ }
+
+ public String getDefaultFormatFrom()
+ {
+ return "&6[&9%s&6 -> &cme&6]&f %m";
+ }
+
+ public String getDefaultFormatTo()
+ {
+ return "&6[&cme&6 -> &9%t&6]&f %m";
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/misc/Misc.cmd b/src/main/java/com/redstoner/modules/misc/Misc.cmd
new file mode 100644
index 0000000..53e73ad
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/misc/Misc.cmd
@@ -0,0 +1,66 @@
+command tempadd {
+ perm pex;
+ [string:user] [string:group] {
+ help Adds a user to a group for 1w.;
+ run tempadddef user group;
+ }
+ [string:user] [string:group] [string:duration] {
+ help Adds a user to a group for a specified duration.;
+ run tempadd user group duration;
+ }
+}
+command echo {
+ [string:text...] {
+ help Echoes back to you.;
+ run echo text;
+ }
+}
+command ping {
+ [empty] {
+ help Pongs :D;
+ run ping;
+ }
+ [string:password] {
+ help Pongs :D;
+ run ping2 password;
+ }
+}
+command sudo {
+ perm utils.sudo;
+ [string:name] [string:command...] {
+ help Sudo'es another user (or console);
+ run sudo name command;
+ }
+}
+command hasperm {
+ [flag:-f] [string:name] [string:node] {
+ perm utils.hasperm;
+ run hasperm -f name node;
+ help Checks if a player has a given permission node or not. Returns \"true/false\" in chat. When -f is set, it returns it unformatted.;
+ }
+}
+command nightvision {
+alias nv;
+ [empty] {
+ run illuminate;
+ type player;
+ help Gives the player infinte night vision;
+ perm utils.illuminate;
+ }
+}
+command minecart {
+ alias cart;
+ perm utils.spawncart;
+ help Spawn's a Minecart;
+ type player;
+
+ deafult [string type] {
+ run minecart_default type;
+ }
+ [string type] {
+ run minecart_type type;
+ }
+ [empty] {
+ run minecart;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/misc/Misc.java b/src/main/java/com/redstoner/modules/misc/Misc.java
new file mode 100644
index 0000000..88e72ea
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/misc/Misc.java
@@ -0,0 +1,336 @@
+package com.redstoner.modules.misc;
+
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.event.block.BlockFromToEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerTeleportEvent;
+import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+import net.nemez.chatapi.ChatAPI;
+import net.nemez.chatapi.click.Message;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Misc implements Module, Listener
+{
+ private final String[] sudoBlacklist = new String[] {"(.*:)?e?sudo", "(.*:)?script.*", "(.*:)?stop",
+ "(.*:)?modules", "(.*:)?sayn", "(.*:)?pex", "(.*:)?console_.*", "(.*:)?op", "(.*:)?login", "(.*:)?register",
+ "(.*:)?.*pass"};
+ JSONObject config;
+ JSONArray unprotectedRegions;
+
+ @EventHandler
+ public void onFirstJoin(PlayerJoinEvent event)
+ {
+ Player player = event.getPlayer();
+ if (!player.hasPlayedBefore())
+ {
+ Utils.broadcast("", "\n§a§lPlease welcome §f" + player.getDisplayName() + " §a§lto Redstoner!\n", null);
+ String[] message = new String[] {" \n \n \n \n \n \n \n \n \n \n \n \n ",
+ " &4Welcome to the Redstoner Server!", " &6Before you ask us things, take a quick",
+ " &6look at &a&nredstoner.com/info", " \n&6thank you and happy playing ;)", " \n \n"};
+ getLogger().message(player, message);
+ }
+ Material spawnBlock = player.getLocation().getBlock().getType();
+ if (spawnBlock == Material.PORTAL || spawnBlock == Material.ENDER_PORTAL)
+ {
+ getLogger().message(player, "&4Looks like you spawned in a portal... Let me help you out");
+ getLogger().message(player, "&6You can use /back if you &nreally&6 want to go back");
+ player.teleport(player.getWorld().getSpawnLocation());
+ }
+ }
+
+ // Disables spectator teleportation
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void onTeleport(PlayerTeleportEvent event)
+ {
+ Player player = event.getPlayer();
+ if (!event.isCancelled() && event.getCause() == TeleportCause.SPECTATE && !player.hasPermission("utils.tp"))
+ {
+ event.setCancelled(true);
+ getLogger().message(event.getPlayer(), true, "Spectator teleportation is disabled!");
+ }
+ }
+
+ // Disables water and lava breaking stuff
+ @EventHandler
+ public void onLiquidFlow(BlockFromToEvent event)
+ {
+ Material m = event.getToBlock().getType();
+ switch (m)
+ {
+ case AIR:
+ case WATER:
+ case STATIONARY_WATER:
+ case LAVA:
+ case STATIONARY_LAVA:
+ return;
+ default:
+ {
+ event.setCancelled(true);
+ }
+ }
+ }
+
+ @Command(hook = "tempadddef")
+ public boolean tempAddDef(CommandSender sender, String user, String group)
+ {
+ return tempAdd(sender, user, group, "604800");
+ }
+
+ @Command(hook = "tempadd")
+ public boolean tempAdd(CommandSender sender, String user, String group, String duration)
+ {
+ // Use it to make a proper duration output later. Too lazy rn.
+ @SuppressWarnings("unused")
+ int i = 0;
+ try
+ {
+ i = Integer.valueOf(duration);
+ }
+ catch (NumberFormatException e)
+ {
+ getLogger().message(sender, true, "That is not a valid number!");
+ return true;
+ }
+ Bukkit.dispatchCommand(sender, "pex user " + user + " group add " + group + " * " + duration);
+ getLogger().message(sender, "Added to group " + group + "for " + duration + " seconds.");
+ return true;
+ }
+
+ @Command(hook = "echo")
+ public boolean echo(CommandSender sender, String text)
+ {
+ sender.sendMessage(ChatAPI.colorify(null, text));
+ return true;
+ }
+
+ @Command(hook = "ping")
+ public boolean ping(CommandSender sender)
+ {
+ if (sender instanceof Player)
+ {
+ int ping = getPing((Player) sender);
+ getLogger().message(sender, "Your ping is " + ping + "ms.");
+ }
+ else
+ {
+ sender.sendMessage("Pong!");
+ }
+ return true;
+ }
+
+ @Command(hook = "ping2")
+ public boolean ping(CommandSender sender, String password)
+ {
+ if (password.equals("pong"))
+ if (sender instanceof Player)
+ {
+ int ping = getPing((Player) sender);
+ getLogger().message(sender, new String[] {"Your ping is " + ping + "ms.", ping < 20
+ ? "&aThat's gr8 m8 r8 8/8"
+ : (ping < 50 ? "F&eair enough you cunt!"
+ : (ping < 100 ? "&eShite, but not shite enough."
+ : "&cLooks like the server is about two months ahead of you. GET A NEW FRIGGIN' ISP ALREADY"))});
+ }
+ else
+ getLogger().message(sender, true,
+ "M8 you shitty cunt are not supposed to run this shit it's for players only!!!");
+ else
+ getLogger().message(sender, true, "&4WRONG PASSWORD, 4/3 ATTEMPTS FAILED! BAN COMMENCING!");
+ return true;
+ }
+
+ public int getPing(Player player)
+ {
+ return ((CraftPlayer) player).getHandle().ping;
+ }
+
+ @Command(hook = "sudo")
+ public boolean sudo(CommandSender sender, String name, String command)
+ {
+ CommandSender target;
+ if (name.equalsIgnoreCase("console"))
+ {
+ target = Bukkit.getConsoleSender();
+ }
+ else
+ target = Bukkit.getPlayer(name);
+ if (target == null)
+ {
+ getLogger().message(sender, false, "That player couldn't be found!");
+ return true;
+ }
+ if (command.startsWith("/") || target.equals(Bukkit.getConsoleSender()))
+ {
+ String[] args = command.split(" ");
+ for (String regex : sudoBlacklist)
+ {
+ if (args[0].matches((target.equals(Bukkit.getConsoleSender()) ? "" : "\\/") + regex))
+ {
+ getLogger().message(sender, true, "You can't sudo anyone into using that command!");
+ return true;
+ }
+ }
+ Bukkit.dispatchCommand(target, command.replaceFirst("/", ""));
+ getLogger().message(sender, "Sudoed " + Utils.getName(target) + "&7 into running " + command);
+ }
+ else
+ {
+ ((Player) target).chat(command);
+ getLogger().message(sender, "Sudoed " + Utils.getName(target) + "&7 into saying " + command);
+ }
+ return true;
+ }
+
+ @Command(hook = "hasperm")
+ public boolean hasPerm(CommandSender sender, boolean noformat, String name, String node)
+ {
+ Player p;
+ if (name.contains("-"))
+ try
+ {
+ p = Bukkit.getPlayer(UUID.fromString(name));
+ }
+ catch (Exception e)
+ {
+ if (noformat)
+ sender.sendMessage("ERR: Invalid UUID");
+ else
+ getLogger().message(sender, "That UUID is not valid!");
+ return true;
+ }
+ else
+ p = Bukkit.getPlayer(name);
+ if (p == null)
+ {
+ if (noformat)
+ {
+ Message m = new Message(sender, null);
+ m.appendText("ERR: Invalid player");
+ m.send();
+ }
+ else
+ {
+ getLogger().message(sender, "That player couldn't be found!");
+ }
+ return true;
+ }
+
+ if (noformat)
+ {
+ Message m = new Message(sender, null);
+ m.appendText("" + p.hasPermission(node));
+ m.send();
+ }
+ else
+ {
+ getLogger().message(sender, "" + p.hasPermission(node));
+ }
+
+ return true;
+ }
+
+ public boolean canBuild(Player player, Location location)
+ {
+ BlockBreakEvent event = new BlockBreakEvent(location.getBlock(), player);
+ Bukkit.getPluginManager().callEvent(event);
+ return event.isCancelled();
+ }
+
+ PotionEffect nightvision = new PotionEffect(PotionEffectType.NIGHT_VISION, Integer.MAX_VALUE, 0, false, false);
+
+ @Command(hook = "illuminate")
+ public void illuminate(CommandSender sender)
+ {
+ Player player = (Player) sender;
+ if (player.hasPotionEffect(PotionEffectType.NIGHT_VISION))
+ {
+ player.removePotionEffect(PotionEffectType.NIGHT_VISION);
+ getLogger().message(sender, "Night Vision Disabled.");
+ }
+ else
+ {
+ player.addPotionEffect(nightvision, true);
+ getLogger().message(sender, "Night Vision Enabled.");
+ }
+ }
+
+ @Command(hook = "minecart")
+ public void minecart(CommandSender sender) {
+ String type = (String) DataManager.getOrDefault(sender, "minecart_default", "normal");
+ minecartDefault(sender, type);
+ }
+
+ @Command(hook = "minecart_type")
+ public void minecartType(CommandSender sender, String type) {
+ Player p = (Player) sender;
+ if (!canBuild(p, p.getLocation())) {
+ ChatAPI.sendActionBar(sender, "&cYou do not have permission to build here!");
+ return;
+ }
+
+ EntityType typeE = convertMinecartTypeString(type);
+
+ if (typeE != null) {
+ p.getWorld().spawnEntity(p.getLocation(), typeE);
+ ChatAPI.sendActionBar(sender, "&aMinecart Spawned!");
+ }
+ else
+ ChatAPI.sendActionBar(sender, "&cThe type of Minecart you've requested does not exist.");
+ }
+
+ @Command(hook = "minecart_default")
+ public void minecartDefault(CommandSender sender, String type) {
+ EntityType typeE = convertMinecartTypeString(type);
+
+ if (typeE != null) {
+ DataManager.setData(sender, "minecart_default", type);
+ ChatAPI.sendActionBar(sender, "&aMinecart Spawned!");
+ }
+ else
+ ChatAPI.sendActionBar(sender, "&cThe type of Minecart you've requested does not exist.");
+ }
+
+ public EntityType convertMinecartTypeString(String type) {
+ EntityType typeE = null;
+
+ switch (type) {
+ case "normal": typeE = EntityType.MINECART;
+ case "chest": typeE = EntityType.MINECART_CHEST;
+ case "furnace": typeE = EntityType.MINECART_FURNACE;
+ case "hopper": typeE = EntityType.MINECART_HOPPER;
+ case "tnt": typeE = EntityType.MINECART_TNT;
+ case "command": typeE = EntityType.MINECART_COMMAND;
+ case "spawner": typeE = EntityType.MINECART_MOB_SPAWNER;
+ }
+
+ return typeE;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/motd/Motd.cmd b/src/main/java/com/redstoner/modules/motd/Motd.cmd
new file mode 100644
index 0000000..987d1fe
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/motd/Motd.cmd
@@ -0,0 +1,14 @@
+command setmotd {
+ [string:motd...] {
+ help Sets the motd. Use --reset to reset to default;
+ run setmotd motd;
+ perm utils.setmotd;
+ }
+}
+command getmotd {
+ [empty] {
+ help Returns the motd;
+ run getmotd;
+ perm utils.getmotd;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/motd/Motd.java b/src/main/java/com/redstoner/modules/motd/Motd.java
new file mode 100644
index 0000000..1334e1a
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/motd/Motd.java
@@ -0,0 +1,59 @@
+package com.redstoner.modules.motd;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.server.ServerListPingEvent;
+
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.Command.AsyncType;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Motd implements Module, Listener
+{
+ private String default_motd, motd;
+
+ @Command(hook = "setmotd", async = AsyncType.ALWAYS)
+ public boolean setMotd(CommandSender sender, String motd)
+ {
+ if (motd.equals("--reset"))
+ this.motd = default_motd;
+ else
+ this.motd = motd;
+ getLogger().message(sender, "The new motd is:\n" + this.motd);
+ return true;
+ }
+
+ @Command(hook = "getmotd", async = AsyncType.ALWAYS)
+ public boolean getMotd(CommandSender sender)
+ {
+ getLogger().message(sender, motd == null ? default_motd : motd);
+ return true;
+ }
+
+ @EventHandler
+ public void onServerPing(ServerListPingEvent event)
+ {
+ event.setMotd(motd);
+ }
+
+ @Override
+ public boolean onEnable()
+ {
+ default_motd = Bukkit.getMotd();
+ if (default_motd == null)
+ {
+ default_motd = "§6Sample text\n§4FIX YOUR SERVER!";
+ }
+ motd = default_motd;
+ return true;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/nametags/Nametags.cmd b/src/main/java/com/redstoner/modules/nametags/Nametags.cmd
new file mode 100644
index 0000000..4095b42
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/nametags/Nametags.cmd
@@ -0,0 +1,11 @@
+command tab {
+ sort {
+ help Resorts the entirety of tab.;
+ run sort;
+ }
+ sort [string:player] {
+ help Resorts one player.;
+ run sortspecific player;
+ }
+ perm utils.tab.admin;
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/nametags/Nametags.java b/src/main/java/com/redstoner/modules/nametags/Nametags.java
new file mode 100644
index 0000000..3a66b18
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/nametags/Nametags.java
@@ -0,0 +1,130 @@
+package com.redstoner.modules.nametags;
+
+import java.util.ArrayList;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.server.ServerCommandEvent;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 2, compatible = 4)
+public class Nametags implements Module, Listener
+{
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event)
+ {
+ sortSpecific(event.getPlayer());
+ }
+
+ @EventHandler
+ public void commandPreprocessEvent(PlayerCommandPreprocessEvent event)
+ {
+ ArrayList<Player> toSort = new ArrayList<>();
+ if (event.getMessage().contains("promote") || event.getMessage().contains("demote")
+ || event.getMessage().matches("pex user .* group (set|add|leave)"))
+ {
+ String[] args = event.getMessage().split(" ");
+ for (String s : args)
+ {
+ Player p = Bukkit.getPlayer(s);
+ if (p != null)
+ toSort.add(p);
+ }
+ }
+ Bukkit.getScheduler().scheduleSyncDelayedTask(Main.plugin, new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ for (Player p : toSort)
+ sortSpecific(p);
+ }
+ });
+ }
+
+ @EventHandler
+ public void consoleCommand(ServerCommandEvent event)
+ {
+ ArrayList<Player> toSort = new ArrayList<>();
+ if (event.getCommand().contains("promote") || event.getCommand().contains("demote")
+ || event.getCommand().matches("pex user .* group (set|add|leave)"))
+ {
+ String[] args = event.getCommand().split(" ");
+ for (String s : args)
+ {
+ Player p = Bukkit.getPlayer(s);
+ if (p != null)
+ toSort.add(p);
+ }
+ }
+ Bukkit.getScheduler().scheduleSyncDelayedTask(Main.plugin, new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ for (Player p : toSort)
+ sortSpecific(p);
+ }
+ });
+ }
+
+ @Command(hook = "sort")
+ public boolean sortAll(CommandSender sender)
+ {
+ for (Player p : Bukkit.getOnlinePlayers())
+ sortSpecific(p);
+ getLogger().message(sender, "Sorted tab for ya!");
+ return true;
+ }
+
+ @Command(hook = "sortspecific")
+ public boolean sortSpecific(CommandSender sender, String player)
+ {
+ Player p = Bukkit.getPlayer(player);
+ if (p == null)
+ {
+ getLogger().message(sender, true, "That player couldn't be found!");
+ return true;
+ }
+ else
+ sortSpecific(p);
+ getLogger().message(sender, "Sorted §e" + player + " §7for ya!");
+ return true;
+ }
+
+ public void sortSpecific(Player player)
+ {
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
+ "scoreboard teams join " + getTeam(player) + " " + player.getName());
+ }
+
+ private String getTeam(Player player)
+ {
+ String[] teams = new String[] {"admin", "mod", "trainingmod", "trusted", "builder", "member", "visitor",
+ "bots"};
+ char prefix = 'a';
+ for (String team : teams)
+ {
+ if (player.hasPermission("group." + team))
+ {
+ return prefix + "_" + team;
+ }
+ prefix++;
+ }
+ return (prefix - 1) + "_" + teams[teams.length - 1];
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/naming/Naming.cmd b/src/main/java/com/redstoner/modules/naming/Naming.cmd
new file mode 100644
index 0000000..1b9bc1a
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/naming/Naming.cmd
@@ -0,0 +1,24 @@
+command anvil {
+ [empty] {
+ run anvil;
+ type player;
+ help Opens anvil GUI.;
+ perm utils.anvil;
+ }
+}
+command name {
+ [string:name...] {
+ run name name;
+ type player;
+ help Names item in hand.;
+ perm utils.name;
+ }
+}
+command lore {
+ [optional:-a] [string:lore...] {
+ run lore -a lore;
+ type player;
+ help Adds lore to item in hand.;
+ perm utils.lore;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/naming/Naming.java b/src/main/java/com/redstoner/modules/naming/Naming.java
new file mode 100644
index 0000000..9564966
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/naming/Naming.java
@@ -0,0 +1,75 @@
+package com.redstoner.modules.naming;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+
+import net.md_5.bungee.api.ChatColor;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Naming implements Module
+{
+ @Command(hook = "anvil")
+ public void anvil(CommandSender sender)
+ {
+ Player player = (Player) sender;
+ Inventory inv = Bukkit.getServer().createInventory(player, InventoryType.ANVIL);
+ player.openInventory(inv);
+ }
+
+ @Command(hook = "name")
+ public void name(CommandSender sender, String name)
+ {
+ name = ChatColor.translateAlternateColorCodes('&', name);
+ ItemStack item = ((Player) sender).getInventory().getItemInMainHand();
+ ItemMeta meta = item.getItemMeta();
+ if (meta == null)
+ {
+ getLogger().message(sender, true, "You can not rename that item!");
+ return;
+ }
+ meta.setDisplayName(name);
+ item.setItemMeta(meta);
+ getLogger().message(sender, "Name set to " + name);
+ ((Player) sender).updateInventory();
+ }
+
+ @Command(hook = "lore")
+ public void lore(CommandSender sender, boolean append, String lore)
+ {
+ ItemStack item = ((Player) sender).getInventory().getItemInMainHand();
+ ItemMeta meta = item.getItemMeta();
+ if (meta == null)
+ {
+ getLogger().message(sender, true, "You can not change the lore of that item!");
+ return;
+ }
+ List<String> currentLore;
+ if (append)
+ currentLore = meta.getLore();
+ else
+ currentLore = new ArrayList<String>();
+ if (currentLore == null)
+ currentLore = new ArrayList<String>();
+ lore = ChatColor.translateAlternateColorCodes('&', lore);
+ currentLore.add(lore);
+ meta.setLore(currentLore);
+ item.setItemMeta(meta);
+ getLogger().message(sender, "Lore set to " + lore);
+ ((Player) sender).updateInventory();
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/onlineplayers/OnlinePlayers.java b/src/main/java/com/redstoner/modules/onlineplayers/OnlinePlayers.java
new file mode 100644
index 0000000..f09d100
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/onlineplayers/OnlinePlayers.java
@@ -0,0 +1,92 @@
+package com.redstoner.modules.onlineplayers;
+
+import java.io.File;
+
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+@AutoRegisterListener
+@Version(major = 4, minor = 0, revision = 3, compatible = 4)
+@SuppressWarnings("unchecked")
+public class OnlinePlayers implements Module, Listener
+{
+ private File saveFile = null;
+ private JSONObject output = null;
+ private JSONArray players = null;
+
+ @Override
+ public void postEnable()
+ {
+ saveFile = new File(Main.plugin.getDataFolder(), "players.json");
+ output = new JSONObject();
+ players = new JSONArray();
+ output.put("dataFormat", "v2");
+ rescan();
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onPlayerJoin(PlayerJoinEvent event)
+ {
+ add(event.getPlayer());
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onPlayerQuit(PlayerQuitEvent event)
+ {
+ remove(event.getPlayer());
+ }
+
+ public void rescan()
+ {
+ players = new JSONArray();
+ for (Player p : Bukkit.getOnlinePlayers())
+ add(p);
+ save();
+ }
+
+ public synchronized void add(Player player)
+ {
+ JSONObject jsonPlayer = new JSONObject();
+ jsonPlayer.put("name", player.getName());
+ jsonPlayer.put("UUID", player.getUniqueId().toString());
+ jsonPlayer.put("joined", System.currentTimeMillis());
+ jsonPlayer.put("vanished", DataManager.getState(player, "vanished"));
+ jsonPlayer.put("afk", DataManager.getState(player, "afk"));
+ players.add(jsonPlayer);
+ save();
+ }
+
+ public synchronized void remove(Player player)
+ {
+ JSONArray toRemove = new JSONArray();
+ for (Object obj : players)
+ {
+ JSONObject o = (JSONObject) obj;
+ if (((String) o.get("UUID")).equals(player.getUniqueId().toString()))
+ toRemove.add(obj);
+ }
+ players.removeAll(toRemove);
+ save();
+ }
+
+ public synchronized void save()
+ {
+ output.put("players", players);
+ output.put("amount", players.size());
+ JsonManager.save((JSONObject) output.clone(), saveFile);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/reports/Reports.cmd b/src/main/java/com/redstoner/modules/reports/Reports.cmd
new file mode 100644
index 0000000..336c418
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/reports/Reports.cmd
@@ -0,0 +1,24 @@
+command report {
+ [string:message...] {
+ type player;
+ help Report a player or incident;
+ run report message;
+ }
+}
+command rp {
+ perm utils.report;
+
+ open {
+ help List all open reports;
+ run report_open;
+ }
+ close [int:id] {
+ help Close a report;
+ run report_close id;
+ }
+ tp [int:id] {
+ help Teleport to the location of a report;
+ run report_tp id;
+ type player;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/reports/Reports.java b/src/main/java/com/redstoner/modules/reports/Reports.java
new file mode 100644
index 0000000..0e55ccc
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/reports/Reports.java
@@ -0,0 +1,154 @@
+package com.redstoner.modules.reports;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+
+import net.md_5.bungee.api.ChatColor;
+
+/** Report module. Allows reports to be created and handled by staff
+ *
+ * @author Redempt */
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Reports implements Module
+{
+ private int task = 0;
+ private JSONArray reports;
+ private JSONArray archived;
+ private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd kk:mm");
+
+ @Override
+ public boolean onEnable()
+ {
+ reports = JsonManager.getArray(new File(Main.plugin.getDataFolder(), "reports.json"));
+ archived = JsonManager.getArray(new File(Main.plugin.getDataFolder(), "archived_reports.json"));
+ if (reports == null)
+ reports = new JSONArray();
+ if (archived == null)
+ archived = new JSONArray();
+ // Notify online staff of open reports
+ task = Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.plugin, () ->
+ {
+ if (reports.size() <= 0)
+ {
+ return;
+ }
+ for (Player player : Bukkit.getOnlinePlayers())
+ {
+ if (player.hasPermission("utils.report"))
+ {
+ getLogger().message(player, "&cThere are &e" + reports.size()
+ + " &copen reports!");
+ }
+ }
+ getLogger().info("&cThere are &e" + reports.size()
+ + " &copen reports!");
+ }, 2400, 2400);
+ return true;
+ }
+
+ @Override
+ public void onDisable()
+ {
+ // Save reports, cancel notifier task
+ Bukkit.getScheduler().cancelTask(task);
+ JsonManager.save(reports, new File(Main.plugin.getDataFolder(), "reports.json"));
+ JsonManager.save(archived, new File(Main.plugin.getDataFolder(), "archived_reports.json"));
+ }
+
+ @Command(hook = "report_tp")
+ public void tpReport(CommandSender sender, int id)
+ {
+ // Check for invalid ID
+ Player player = (Player) sender;
+ if (id > reports.size() - 1 || id < 0)
+ {
+ getLogger().message(sender, true, "Invalid ID!");
+ return;
+ }
+ JSONObject report = (JSONObject) reports.get(id);
+ String loc = (String) report.get("location");
+ String[] split = loc.split(";");
+ // Location from string
+ int x = Integer.parseInt(split[0]);
+ int y = Integer.parseInt(split[1]);
+ int z = Integer.parseInt(split[2]);
+ World world = Bukkit.getWorld(split[3]);
+ Location location = new Location(world, x, y, z);
+ player.teleport(location);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "report_close")
+ public void closeReport(CommandSender sender, int id)
+ {
+ // Check for invalid ID
+ if (id > reports.size() - 1 || id < 0)
+ {
+ getLogger().message(sender, true, "Invalid ID!");
+ return;
+ }
+ // Move report to archived reports
+ JSONObject report = (JSONObject) reports.get(id);
+ reports.remove(id);
+ archived.add(report);
+ sender.sendMessage(ChatColor.GREEN + "Report #" + id + " closed!");
+ }
+
+ @Command(hook = "report_open")
+ public void listOpen(CommandSender sender)
+ {
+ int i = 0;
+ for (Object object : reports)
+ {
+ JSONObject report = (JSONObject) object;
+ String message = "";
+ message += ChatColor.DARK_GRAY + "[" + ChatColor.YELLOW + i + ChatColor.DARK_GRAY + "]";
+ message += "[" + ChatColor.YELLOW + report.get("time") + ChatColor.DARK_GRAY + "] ";
+ message += ChatColor.DARK_AQUA + "" + report.get("name");
+ message += ChatColor.WHITE + ": " + ChatColor.YELLOW + report.get("message");
+ sender.sendMessage(message);
+ i++;
+ }
+ if (i == 0)
+ {
+ sender.sendMessage(ChatColor.GREEN + "There are no open reports.");
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "report")
+ public void report(CommandSender sender, String message)
+ {
+ Player player = (Player) sender;
+ // Create report JSONObject
+ JSONObject report = new JSONObject();
+ report.put("name", player.getName());
+ report.put("time", dateFormat.format(new Date()));
+ report.put("message", message);
+ String loc = "";
+ // Location to string
+ loc += player.getLocation().getBlockX() + ";" + player.getLocation().getBlockY() + ";"
+ + player.getLocation().getBlockZ() + ";" + player.getLocation().getWorld().getName();
+ report.put("location", loc);
+ reports.add(report);
+ sender.sendMessage(ChatColor.GREEN + "Report created!");
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/saylol/Saylol.cmd b/src/main/java/com/redstoner/modules/saylol/Saylol.cmd
new file mode 100644
index 0000000..8cc4d44
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/saylol/Saylol.cmd
@@ -0,0 +1,47 @@
+command lol {
+ add [string:text...] {
+ help Lols a text.;
+ run addlol text;
+ perm utils.lol.admin;
+ }
+ del [int:id] {
+ help Unlols a lol.;
+ run dellol id;
+ perm utils.lol.admin;
+ }
+ set [int:id] [string:text...] {
+ help Relols a lol.;
+ run setlol id text;
+ perm utils.lol.admin;
+ }
+ id [int:id] {
+ help Lols specifically.;
+ run lolid id;
+ perm utils.lol.id;
+ }
+ list [int:page] {
+ help Shows lols.;
+ run listlols page;
+ perm utils.lol.list;
+ }
+ list {
+ help Shows lols.;
+ run listlolsdef;
+ perm utils.lol.list;
+ }
+ search [flag:-i] [string:text...] {
+ help Search lols.;
+ run searchlol -i text;
+ perm utils.lol.search;
+ }
+ match [flag:-i] [string:regex...] {
+ help Search lols. But better.;
+ run matchlol -i regex;
+ perm utils.lol.match;
+ }
+ [empty] {
+ help Lols.;
+ run saylol;
+ perm utils.lol;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/saylol/Saylol.java b/src/main/java/com/redstoner/modules/saylol/Saylol.java
new file mode 100644
index 0000000..7081aec
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/saylol/Saylol.java
@@ -0,0 +1,300 @@
+package com.redstoner.modules.saylol;
+
+import java.io.File;
+import java.util.Random;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.json.simple.JSONArray;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.BroadcastFilter;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.ignore.Ignore;
+
+import net.nemez.chatapi.ChatAPI;
+import net.nemez.chatapi.click.ClickCallback;
+import net.nemez.chatapi.click.Message;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Saylol implements Module
+{
+ private long lastLol = 0;
+ private File lolLocation = new File(Main.plugin.getDataFolder(), "lol.json");
+ private JSONArray lols, handlers;
+ private final String LOL_PREFIX = "§8[§blol§8] ";
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean onEnable()
+ {
+ lols = JsonManager.getArray(lolLocation);
+ if (lols == null)
+ lols = new JSONArray();
+ handlers = new JSONArray();
+ for (int i = 0; i < lols.size(); i++)
+ handlers.add(new ClickCallback(true, true, "")
+ {
+ @Override
+ public void run(CommandSender sender)
+ {
+ if (handlers.contains(this))
+ clickAction((Player) sender, handlers.indexOf(this));
+ else
+ getLogger().message(sender, true, "That lol no longer exists!");
+ }
+ });
+ return true;
+ }
+
+ @Override
+ public void onDisable()
+ {
+ saveLolsSync();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "addlol")
+ public boolean addLol(CommandSender sender, String text)
+ {
+ if (lols.contains(text))
+ getLogger().message(sender, true, "This lol already exists!");
+ else
+ {
+ getLogger().message(sender, "Successfully added a new lol!");
+ lols.add("&e" + text);
+ handlers.add(new ClickCallback(true, true, "")
+ {
+ @Override
+ public void run(CommandSender sender)
+ {
+ if (handlers.contains(this))
+ clickAction((Player) sender, handlers.indexOf(this));
+ else
+ getLogger().message(sender, true, "That lol no longer exists!");
+ }
+ });
+ saveLols();
+ }
+ return true;
+ }
+
+ @Command(hook = "dellol")
+ public boolean delLol(CommandSender sender, int id)
+ {
+ if (lols.size() == 0)
+ {
+ getLogger().message(sender, true, "There are no lols yet!");
+ return true;
+ }
+ if (id < 0 || id >= lols.size())
+ {
+ getLogger().message(sender, true, "The ID must be at least 0 and at most " + (lols.size() - 1));
+ return true;
+ }
+ getLogger().message(sender, "Successfully deleted the lol: " + lols.remove(id));
+ handlers.remove(id);
+ saveLols();
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "setlol")
+ public boolean setLol(CommandSender sender, int id, String text)
+ {
+ if (lols.size() == 0)
+ {
+ getLogger().message(sender, true, "There are no lols yet!");
+ return true;
+ }
+ if (id < 0 || id >= lols.size())
+ {
+ getLogger().message(sender, true, "The ID must be at least 0 and at most " + (lols.size() - 1));
+ return true;
+ }
+ getLogger().message(sender, "Successfully changed the lol: &e" + lols.get(id) + " &7to: &e" + text);
+ lols.set(id, text);
+ saveLols();
+ return true;
+ }
+
+ @Command(hook = "lolid")
+ public boolean lolId(CommandSender sender, int id)
+ {
+ if (lols.size() == 0)
+ {
+ getLogger().message(sender, true, "There are no lols yet!");
+ return true;
+ }
+ long time = System.currentTimeMillis();
+ if (time - lastLol < 15000)
+ {
+ getLogger().message(sender, true,
+ "You can't use saylol for another " + (14 - (int) Math.ceil((time - lastLol) / 1000)) + "s.");
+ return true;
+ }
+ if (id < 0 || id >= lols.size())
+ {
+ getLogger().message(sender, true, "The ID must be at least 0 and at most " + (lols.size() - 1));
+ return true;
+ }
+ String name;
+ if (sender instanceof Player)
+ name = ((Player) sender).getDisplayName();
+ else
+ name = "&9" + sender.getName();
+ Utils.broadcast(LOL_PREFIX, ChatAPI.colorify(null, name + "&8: &e" + lols.get(id)), new BroadcastFilter()
+ {
+ @Override
+ public boolean sendTo(CommandSender recipient)
+ {
+ return recipient.hasPermission("utils.lol.see");
+ }
+ });
+ lastLol = time;
+ return true;
+ }
+
+ @Command(hook = "saylol")
+ public boolean saylol(CommandSender sender)
+ {
+ if (lols.size() == 0)
+ {
+ getLogger().message(sender, true, "There are no lols yet!");
+ return true;
+ }
+ long time = System.currentTimeMillis();
+ if (time - lastLol < 15000)
+ {
+ getLogger().message(sender, true,
+ "You can't use saylol for another " + (14 - (int) Math.ceil((time - lastLol) / 1000)) + "s.");
+ return true;
+ }
+ String name;
+ if (sender instanceof Player)
+ name = ((Player) sender).getDisplayName();
+ else
+ name = "&9" + sender.getName();
+ Random random = new Random();
+ int id = random.nextInt(lols.size());
+ Utils.broadcast(LOL_PREFIX, ChatAPI.colorify(null, name + "&8: &e" + lols.get(id)),
+ ModuleLoader.exists("Ignore")? Ignore.getIgnoredBy(sender) : null);
+ lastLol = time;
+ return true;
+ }
+
+ @Command(hook = "listlols")
+ public boolean listLols(CommandSender sender, int page)
+ {
+ if (lols.size() == 0)
+ {
+ getLogger().message(sender, true, "There are no lols yet!");
+ return true;
+ }
+ page = page - 1;
+ int start = page * 10;
+ int end = start + 10;
+ int pages = (int) Math.ceil(lols.size() / 10d);
+ if (start < 0)
+ {
+ getLogger().message(sender, true, "Page number too small, must be at least 0!");
+ return true;
+ }
+ if (start > lols.size())
+ {
+ getLogger().message(sender, true, "Page number too big, must be at most " + pages + "!");
+ return true;
+ }
+ Message m = new Message(sender, null);
+ m.appendText(getLogger().getHeader().replace("\n", ""));
+ m.appendText("&ePage " + (page + 1) + "/" + pages + ":");
+ for (int i = start; i < end && i < lols.size(); i++)
+ m.appendCallback("\n&a" + i + "&8: &e" + lols.get(i), getCallback(i));
+ m.send();
+ return true;
+ }
+
+ @Command(hook = "listlolsdef")
+ public boolean listLolsDefault(CommandSender sender)
+ {
+ return listLols(sender, 1);
+ }
+
+ @Command(hook = "searchlol")
+ public boolean search(CommandSender sender, boolean sensitive, String text)
+ {
+ Message m = new Message(sender, null);
+ m.appendText(getLogger().getHeader().replace("\n", ""));
+ boolean found = false;
+ if (!sensitive)
+ text = text.toLowerCase();
+ for (int i = 0; i < lols.size(); i++)
+ {
+ String lol = (String) lols.get(i);
+ if ((sensitive ? lol : lol.toLowerCase()).contains(text))
+ {
+ m.appendCallback("\n&a" + i + "&8: &e" + lol, getCallback(i));
+ found = true;
+ }
+ }
+ if (!found)
+ getLogger().message(sender, "&cCouldn't find any matching lols.");
+ else
+ m.send();
+ return true;
+ }
+
+ @Command(hook = "matchlol")
+ public boolean match(CommandSender sender, boolean sensitive, String regex)
+ {
+ Message m = new Message(sender, null);
+ m.appendText(getLogger().getHeader().replace("\n", ""));
+ boolean found = false;
+ if (!sensitive)
+ regex = regex.toLowerCase();
+ for (int i = 0; i < lols.size(); i++)
+ {
+ String lol = (String) lols.get(i);
+ if ((sensitive ? lol : lol.toLowerCase()).matches(regex))
+ {
+ m.appendCallback("\n&a" + i + "&8: &e" + lol, getCallback(i));
+ found = true;
+ }
+ }
+ if (!found)
+ getLogger().message(sender, "&cCouldn't find any matching lols.");
+ else
+ m.send();
+ return true;
+ }
+
+ public void saveLols()
+ {
+ JsonManager.save(lols, lolLocation);
+ }
+
+ public void saveLolsSync()
+ {
+ JsonManager.saveSync(lols, lolLocation);
+ }
+
+ public ClickCallback getCallback(int index)
+ {
+ return (ClickCallback) handlers.get(index);
+ }
+
+ public void clickAction(Player player, int index)
+ {
+ if (player.hasPermission("utils.lol.id"))
+ Bukkit.dispatchCommand(player, "lol id " + index);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/scriptutils/Scriptutils.cmd b/src/main/java/com/redstoner/modules/scriptutils/Scriptutils.cmd
new file mode 100644
index 0000000..c8498b2
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/scriptutils/Scriptutils.cmd
@@ -0,0 +1,119 @@
+command script_restart {
+ [string:timeout] [string:name] [string:reason] {
+ help Prints bukkit restart message;
+ type console;
+ run script_restart timeout name reason;
+ }
+}
+command script_stop {
+ [string:timeout] [string:name] [string:reason] {
+ help Prints bukkit shut down message;
+ type console;
+ run script_stop timeout name reason;
+ }
+}
+command script_restart_abort {
+ [empty] {
+ help Prints the restart abort message;
+ type console;
+ run script_restart_abort;
+ }
+}
+command script_stop_abort {
+ [empty] {
+ help Prints the shut down abort message;
+ type console;
+ run script_stop_abort;
+ }
+}
+command script_backup_begin {
+ [empty] {
+ help Prints the backup started message, saves all worlds and turns off world saving;
+ type console;
+ run script_backup_begin;
+ }
+}
+command script_backup_end {
+ [empty] {
+ help Prints the backup finished message and turns on world saving;
+ type console;
+ run script_backup_end;
+ }
+}
+command script_backup_error {
+ [empty] {
+ help Prints the backup error message and turns on world saving;
+ type console;
+ run script_backup_error;
+ }
+}
+command script_trim {
+ [empty] {
+ help Prints the world trimming started message and starts trimming;
+ type console;
+ run script_trim;
+ }
+}
+command script_trim_result {
+ [string:size] [string:data...] {
+ help Prints the trimming finished message;
+ type console;
+ run script_trim_result size data;
+ }
+}
+command script_backup_database_begin {
+ [empty] {
+ help Prints the database backup started message and admin-chat warning;
+ type console;
+ run script_backup_database_begin;
+ }
+}
+command script_backup_database_dumps {
+ [empty] {
+ help Prints the database dumps cmpression started message;
+ type console;
+ run script_backup_database_dumps;
+ }
+}
+command script_backup_database_end {
+ [string:size] {
+ help Prints the database finished message and backup size in admin-chat;
+ type console;
+ run script_backup_database_end size;
+ }
+}
+command script_backup_database_error {
+ [empty] {
+ help Prints the database backup error message;
+ type console;
+ run script_backup_database_error;
+ }
+}
+command script_backup_database_abort {
+ [empty] {
+ help Prints the database backup abort message;
+ type console;
+ run script_backup_database_abort;
+ }
+}
+command script_spigot_update {
+ [empty] {
+ help Prints the spigot update message;
+ type console;
+ run script_spigot_update;
+ }
+}
+command script_disk_filled {
+ [string:percentage] {
+ help Prints the admin-chat warning for disk is filled;
+ type console;
+ run script_disk_filled percentage;
+ }
+}
+command script_shutdown {
+ [string:reason] {
+ help Saves all worlds, kicks players and shuts down the server;
+ type console;
+ run script_shutdown reason;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/scriptutils/Scriptutils.java b/src/main/java/com/redstoner/modules/scriptutils/Scriptutils.java
new file mode 100644
index 0000000..1d634c0
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/scriptutils/Scriptutils.java
@@ -0,0 +1,177 @@
+package com.redstoner.modules.scriptutils;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Scriptutils implements Module
+{
+ /** Prints Bukkit restart message
+ * arg 0 timeout
+ * arg 1 $(whoami);
+ * arg 2: reason */
+ @Command(hook = "script_restart")
+ public void print_restart(CommandSender sender, String timeout, String name, String reason)
+ {
+ Utils.broadcast("", "§2§l=============================================", null);
+ Utils.broadcast("", "§r", null);
+ Utils.broadcast("", "§r", null);
+ Utils.broadcast("", "§9" + name + " is restarting the server.", null);
+ Utils.broadcast("", "§a§lServer is going to restart in " + timeout + " seconds.", null);
+ Utils.broadcast("", "§6§l" + reason, null);
+ Utils.broadcast("", "§r", null);
+ Utils.broadcast("", "§r", null);
+ Utils.broadcast("", "§2§l=============================================", null);
+ }
+
+ /** Prints the Bukkit shut down message
+ * arg 0 timeout
+ * arg 1 $(whoami);
+ * arg 2: reason */
+ @Command(hook = "script_stop")
+ public void print_stop(CommandSender sender, String timeout, String name, String reason)
+ {
+ Utils.broadcast("", "§2§l=============================================", null);
+ Utils.broadcast("", "§r", null);
+ Utils.broadcast("", "§r", null);
+ Utils.broadcast("", "§9" + name + " is shutting down the server.", null);
+ Utils.broadcast("", "§a§lServer is going to shut down in " + timeout + " seconds.", null);
+ Utils.broadcast("", "§6§l" + reason, null);
+ Utils.broadcast("", "§r", null);
+ Utils.broadcast("", "§r", null);
+ Utils.broadcast("", "§2§l=============================================", null);
+ }
+
+ /** Prints the shut down abort message */
+ @Command(hook = "script_stop_abort")
+ public void abort_stop(CommandSender sender)
+ {
+ Utils.broadcast("", "§4§oShut down has been aborted.", null);
+ }
+
+ /** Prints the restart abort message */
+ @Command(hook = "script_restart_abort")
+ public void abort_restart(CommandSender sender)
+ {
+ Utils.broadcast("", "§4§oRestart has been aborted.", null);
+ }
+
+ /** Prints the backup started message, saves all worlds and turns off world saving */
+ @Command(hook = "script_backup_begin")
+ public void print_backup_begin(CommandSender sender)
+ {
+ Utils.broadcast("", "§4 =§2 Starting backup now.", null);
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "save-all");
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "save-off");
+ }
+
+ /** Prints the backup finished message and turns on world saving */
+ @Command(hook = "script_backup_end")
+ public void print_backup_end(CommandSender sender)
+ {
+ Utils.broadcast("", "§4 =§2 Backup completed.", null);
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "save-on");
+ }
+
+ /** Prints the backup error message and turns on world saving */
+ @Command(hook = "script_backup_error")
+ public void print_backup_error(CommandSender sender)
+ {
+ Utils.broadcast("", "§4 =§c§l Error while backing up!", null);
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "save-on");
+ }
+
+ /** Prints the world trimming started message and starts trimming */
+ @Command(hook = "script_trim")
+ public void print_backup_trim(CommandSender sender)
+ {
+ Utils.broadcast("", "§4 =§3 Deleting all chunks beyond border now.", null);
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "wb Creative trim 1000000 15");
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "wb trim confirm");
+ }
+
+ /** Prints the trimming finished message
+ * arg 0 size difference of world
+ * arg 1: world border trim data */
+ @Command(hook = "script_trim_result")
+ public void print_backup_trim_res(CommandSender sender, String size, String data)
+ {
+ Utils.broadcast("", "§4 =§3 Chunk deletion saved " + data + " (§a" + size + "MB§3)", null);
+ }
+
+ /** Prints the database backup started message and admin-chat warning */
+ @Command(hook = "script_backup_database_begin")
+ public void print_backup_db_begin(CommandSender sender)
+ {
+ Utils.broadcast("", "§6 =§2 Starting database backup now.", null);
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ac §aLogblock may be unavailable!");
+ }
+
+ /** Prints the database dumps compression started message */
+ @Command(hook = "script_backup_database_dumps")
+ public void print_backup_db_dumps(CommandSender sender)
+ {
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ac §aDumps completed, logblock available again.");
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ac §aNow compressing dumps, will take a while...");
+ }
+
+ /** Prints the database finished message and backup size in admin-chat
+ * arg 0 size of backup */
+ @Command(hook = "script_backup_database_end")
+ public void print_backup_db_end(CommandSender sender, String size)
+ {
+ Utils.broadcast("", "§6 =§2 Database backup completed.", null);
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ac §abackup size: §2" + size + "MB§a.");
+ }
+
+ /** Prints the database backup error message */
+ @Command(hook = "script_backup_database_error")
+ public void print_backup_db_error(CommandSender sender)
+ {
+ Utils.broadcast("", "§6 =§c§l Error while backing up database!", null);
+ }
+
+ /** Prints the database backup abort message */
+ @Command(hook = "script_backup_database_abort")
+ public void print_backup_db_abort(CommandSender sender)
+ {
+ Utils.broadcast("", "§6 =§2 Database backup aborted.", null);
+ }
+
+ /** Prints the spigot update message */
+ @Command(hook = "script_spigot_update")
+ public void print_update(CommandSender sender)
+ {
+ Utils.broadcast("", "§9 =§2 A new Spigot version has been downloaded!", null);
+ Utils.broadcast("", "§9 =§2 Update will be applied after the next reboot.", null);
+ }
+
+ /** Prints the admin-chat warning for disk is filled
+ * arg 0 fill percentage */
+ @Command(hook = "script_disk_filled")
+ public void print_disk_filled(CommandSender sender, String percentage)
+ {
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
+ "ac §4§lWARNING:§6 Disk is filled > 96% (" + percentage + "%);");
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ac §4 Server will shut down at 98%!");
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "ac §4 Contact an admin §nimmediately§4!");
+ }
+
+ /** Saves all worlds, kicks players and shuts down the server
+ * arg 0: reason */
+ @Command(hook = "script_shutdown")
+ public void shutdown(CommandSender sender, String reason)
+ {
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "save-all");
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "kickall " + reason);
+ Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "stop");
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/seen/Seen.cmd b/src/main/java/com/redstoner/modules/seen/Seen.cmd
new file mode 100644
index 0000000..d17e655
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/seen/Seen.cmd
@@ -0,0 +1,53 @@
+command seen {
+ [string:player] {
+ help Displays information about a player.;
+ perm utils.seen;
+ run seen player;
+ }
+
+ [string:player] [flag:ips] {
+ help Displays information about a player.;
+ perm utils.seen;
+ run seen2 player ips;
+ }
+}
+command firstseen {
+ [empty] {
+ run firstseen;
+ type player;
+ help Gives the date and time they first joined;
+ perm utils.firstseen;
+ }
+ [string:person] {
+ run firstseenP person;
+ help Gives the date and time when a player first joined;
+ perm utils.firstseen.other;
+ }
+}
+command playtime {
+ [empty] {
+ type player;
+ run playtimeDef;
+ perm utils.playtime;
+ help Displays your total playtime!;
+ }
+ [string:name] {
+ run playtime name;
+ perm utils.playtime.others;
+ help Displays the playtime of another player. The player must be online!;
+ }
+}
+
+command uuid {
+ [empty] {
+ type player;
+ run uuidDef;
+ perm utils.uuid;
+ help Displays your UUID (click to copy);
+ }
+ [string:name] {
+ run uuid name;
+ perm utils.uuid.other;
+ help Displays someone elses UUID (click to copy);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/seen/Seen.java b/src/main/java/com/redstoner/modules/seen/Seen.java
new file mode 100644
index 0000000..ed3324c
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/seen/Seen.java
@@ -0,0 +1,320 @@
+package com.redstoner.modules.seen;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.Statistic;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.earth2me.essentials.utils.DateUtil;
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.Command.AsyncType;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+import net.nemez.chatapi.click.Message;
+
+@AutoRegisterListener
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 10, compatible = 4)
+public class Seen implements Module, Listener
+{
+ HashMap<UUID, JSONArray> names = new HashMap<>();
+ HashMap<UUID, JSONArray> ips = new HashMap<>();
+
+ @Override
+ public void postEnable()
+ {
+ Module.super.postEnable();
+ for (Player player : Bukkit.getOnlinePlayers())
+ loadData(player);
+ }
+
+ @Command(hook = "seen", async = AsyncType.ALWAYS)
+ public boolean seen(CommandSender sender, String player)
+ {
+ return seen(sender, player, false);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Command(hook = "seen2", async = AsyncType.ALWAYS)
+ public boolean seen(CommandSender sender, String player, boolean show_ips)
+ {
+ ArrayList<String> message = new ArrayList<>();
+ OfflinePlayer p;
+ if (Utils.isUUID(player))
+ p = Bukkit.getOfflinePlayer(UUID.fromString(player));
+ else
+ p = Bukkit.getPlayer(player);
+ boolean cansee = (sender instanceof Player ? p instanceof Player && ((Player) sender).canSee((Player) p)
+ : true);
+ if (p == null)
+ {
+ p = Bukkit.getOfflinePlayer(player);
+ if (p != null)
+ p = Bukkit.getOfflinePlayer(p.getUniqueId());
+ }
+ if (p == null || (!p.isOnline() && !p.hasPlayedBefore()) || (!cansee && !p.getName().equalsIgnoreCase(player)))
+ {
+ getLogger().message(sender, true, "§e" + player + "§7 has never joined the server!");
+ return true;
+ }
+ boolean online = cansee ? p instanceof Player : false;
+ String state;
+ long timestamp;
+ if (online)
+ {
+ state = "&aonline";
+ timestamp = (long) DataManager.getData(p.getUniqueId().toString(), "lastjoined");
+ }
+ else
+ {
+ state = "&coffline";
+ timestamp = (long) DataManager.getOrDefault(p.getUniqueId().toString(), "lastquit", p.getLastPlayed());
+ }
+ String time = DateUtil.formatDateDiff(timestamp);
+ message.add("&e" + p.getName() + " &7has been " + state + " &7for &e" + time + "&7.");
+ JSONArray _names;
+ if (online)
+ {
+ if (DataManager.getState((Player) p, "afk"))
+ {
+ message.add("They're currently &eAFK&7:");
+ String reason = (String) DataManager.getOrDefault(p.getUniqueId().toString(), "AFK", "afk_reason", "");
+ Long timeAFK = (Long) DataManager.getOrDefault(p.getUniqueId().toString(), "AFK", "afk_time", 0L);
+
+ message.add(" &9For: " + DateUtil.formatDateDiff(timeAFK));
+ if (reason.length() >= 1)
+ message.add(" &9Reason: " + reason);
+ }
+ if (DataManager.getState((Player) p, "vanished"))
+ message.add("They're currently &evanished&7!");
+ _names = names.get(p.getUniqueId());
+ }
+ else
+ {
+ _names = loadNames(p.getUniqueId());
+ }
+ if (_names != null && _names.size() > 1)
+ message.add("They've also been known as: &e"
+ + _names.toJSONString().replaceAll("[\"\\[\\]]", "").replace(",", "&7, &e"));
+ if (sender.hasPermission("utils.seen.ip"))
+ {
+ if (show_ips)
+ {
+ JSONArray _ips;
+ if (online)
+ _ips = ips.get(p.getUniqueId());
+ else
+ _ips = loadIPs(p.getUniqueId());
+ if (_ips != null && _ips.size() > 0)
+ message.add("They've joined with the following IPs: &e"
+ + _ips.toJSONString().replaceAll("[\"\\[\\]]", "").replace(",", "&7, &e"));
+ }
+ message.add(
+ "Their current IP is: &a" + DataManager.getOrDefault(p.getUniqueId().toString(), "ip", "unknown"));
+ }
+ getLogger().message(sender, message.toArray(new String[] {}));
+ return true;
+ }
+
+ @EventHandler
+ public void onPlayerJoin(PlayerJoinEvent event)
+ {
+ DataManager.setData(event.getPlayer(), "lastjoined", System.currentTimeMillis());
+ DataManager.setData(event.getPlayer(), "ip", event.getPlayer().getAddress().getHostString());
+ loadData(event.getPlayer());
+ }
+
+ @EventHandler
+ public void onPlayerQuit(PlayerQuitEvent event)
+ {
+ DataManager.setData(event.getPlayer(), "lastquit", System.currentTimeMillis());
+ unloadData(event.getPlayer());
+ }
+
+ @SuppressWarnings("unchecked")
+ public void loadData(Player player)
+ {
+ Thread t = new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ File jsonfile = new File(Main.plugin.getDataFolder(), "/seen/" + Utils.getID(player) + ".json");
+ JSONObject json = JsonManager.getObject(jsonfile);
+ if (json == null)
+ {
+ json = new JSONObject();
+ json.put("names", new JSONArray());
+ json.put("ips", new JSONArray());
+ }
+ JSONArray lnames = (JSONArray) json.get("names");
+ if (!lnames.contains(player.getName()))
+ lnames.add(player.getName());
+ json.put("names", lnames);
+
+ JSONArray lips = (JSONArray) json.get("ips");
+ String ip = player.getAddress().getHostString();
+ if (!lips.contains(ip))
+ lips.add(ip);
+ json.put("ips", lips);
+
+ names.put(player.getUniqueId(), lnames);
+ ips.put(player.getUniqueId(), lips);
+ JsonManager.save(json, jsonfile);
+ }
+ });
+ t.start();
+ }
+
+ public void unloadData(Player player)
+ {
+ this.names.remove(player.getUniqueId());
+ this.ips.remove(player.getUniqueId());
+ }
+
+ public JSONArray loadNames(UUID uuid)
+ {
+ File jsonfile = new File(Main.plugin.getDataFolder(), "/seen/" + uuid + ".json");
+ JSONObject json = JsonManager.getObject(jsonfile);
+ if (json == null)
+ return null;
+ else
+ return (JSONArray) json.get("names");
+ }
+
+ public JSONArray loadIPs(UUID uuid)
+ {
+ File jsonfile = new File(Main.plugin.getDataFolder(), "/seen/" + uuid + ".json");
+ JSONObject json = JsonManager.getObject(jsonfile);
+ if (json == null)
+ return null;
+ else
+ return (JSONArray) json.get("ips");
+ }
+
+ @SuppressWarnings("deprecation")
+ @Command(hook = "firstseenP")
+ public void firstseen(CommandSender sender, String person)
+ {
+ OfflinePlayer oPlayer = Bukkit.getPlayer(person);
+ if (oPlayer == null)
+ oPlayer = Bukkit.getServer().getOfflinePlayer(person);
+ Long firstJoin = oPlayer.getFirstPlayed();
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+ String disDate = format.format(new Date(firstJoin));
+ if (disDate.equals("1970-01-01 00:00"))
+ {
+ getLogger().message(sender, true, "&3" + oPlayer.getName() + "&c has never joined.");
+ }
+ else
+ {
+ getLogger().message(sender, "&3" + oPlayer.getName() + " &efirst joined&a " + disDate + "&e.");
+ }
+ }
+
+ @Command(hook = "firstseen")
+ public void firstseen(CommandSender sender)
+ {
+ firstseen(sender, sender.getName());
+ }
+
+ @Command(hook = "playtimeDef")
+ public boolean playtime(CommandSender sender)
+ {
+ return playtime(sender, sender.getName());
+ }
+
+ @Command(hook = "playtime")
+ public boolean playtime(CommandSender sender, String name)
+ {
+ if (name == null)
+ name = sender.getName();
+ Player player = Bukkit.getPlayer(name);
+ if (player == null)
+ {
+ getLogger().message(sender, true, "§e" + name
+ + "§7 couldn't be found! Hint: Currently, you can only check statistics of players that are online!");
+ return true;
+ }
+ int ticks_lived = player.getStatistic(Statistic.PLAY_ONE_TICK);
+ int days = ticks_lived / 1728000;
+ int hours = (ticks_lived % 1728000) / 72000;
+ int minutes = (ticks_lived % 72000) / 1200;
+ if (sender.getName().equals(name))
+ {
+ getLogger().message(sender,
+ "You have played for &b"
+ + (days == 0 && hours == 0 && minutes == 0 ? "less than a minute."
+ : ("a total of: &e" + (days != 0 ? (days + "d ") : "")
+ + ((hours != 0 || days != 0) ? (hours + "h ") : "")
+ + ((minutes != 0 || hours != 0 || days != 0) ? (minutes + "m") : "")))
+ + "&7.");
+ }
+ else
+ {
+ getLogger().message(sender, "&3" + name + " &7has played for "
+ + (days == 0 && hours == 0 && minutes == 0 ? "less than a minute."
+ : ("a total of: &e" + (days != 0 ? (days + "d ") : "")
+ + ((hours != 0 || days != 0) ? (hours + "h ") : "")
+ + ((minutes != 0 || hours != 0 || days != 0) ? (minutes + "m") : "")))
+ + "&7.");
+ }
+ return true;
+ }
+
+ @Command(hook = "uuidDef")
+ public boolean uuid(CommandSender sender)
+ {
+ Player player = (Player) sender;
+ Message m = new Message(sender, null);
+ m.appendText(getLogger().getPrefix());
+ m.appendSuggestHover("&6> UUID: &e" + player.getUniqueId().toString(), player.getUniqueId().toString(),
+ "Click to copy into chatbox!");
+ m.send();
+ return true;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Command(hook = "uuid")
+ public boolean uuid(CommandSender sender, String name)
+ {
+ OfflinePlayer player = Bukkit.getPlayer(name);
+ if (player == null)
+ {
+ player = Bukkit.getOfflinePlayer(name);
+ if (player == null)
+ {
+ getLogger().error("That player couldn't be found!");
+ return true;
+ }
+ }
+ Message m = new Message(sender, null);
+ m.appendText(getLogger().getPrefix());
+ m.appendSuggestHover("&6> UUID: &e" + player.getUniqueId().toString(), player.getUniqueId().toString(),
+ "Click to copy into chatbox!");
+ m.send();
+ return true;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/signalstrength/SignalStrength.cmd b/src/main/java/com/redstoner/modules/signalstrength/SignalStrength.cmd
new file mode 100644
index 0000000..1cfb0fd
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/signalstrength/SignalStrength.cmd
@@ -0,0 +1,14 @@
+command signalstrength {
+ alias ss;
+ perm utils.signalstrength;
+ [int:strength] {
+ run ss strength;
+ type player;
+ help "Sets the amount of items in a container to achieve the given signal strength. Uses redstone dust.";
+ }
+ [int:strength] [string:material] {
+ run ssm strength material;
+ type player;
+ help "Sets the amount of itmes in a container to achieve the given signal strength. Uses the material specified.";
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/signalstrength/SignalStrength.java b/src/main/java/com/redstoner/modules/signalstrength/SignalStrength.java
new file mode 100644
index 0000000..b613b09
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/signalstrength/SignalStrength.java
@@ -0,0 +1,194 @@
+package com.redstoner.modules.signalstrength;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Set;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.GameMode;
+import org.bukkit.Material;
+import org.bukkit.Nameable;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
+import org.bukkit.block.BlockState;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.block.BlockPlaceEvent;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.InventoryHolder;
+import org.bukkit.inventory.ItemStack;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 2, compatible = 4)
+public class SignalStrength implements Module
+{
+
+ private static final String namePrefix = ChatColor.GREEN.toString() + ChatColor.RESET + ChatColor.DARK_PURPLE
+ + "Signal Strength: " + ChatColor.RED + ChatColor.BOLD;
+
+ private static String nameForSignalStrength(int strength)
+ {
+ return namePrefix + strength;
+ }
+
+ private static boolean isSignalStrengthNameOrEmpty(String name)
+ {
+ return name == null || name.isEmpty() || name.startsWith(namePrefix);
+ }
+
+ @Command(hook = "ss")
+ public boolean ss(CommandSender sender, int strength)
+ {
+ return ssm(sender, strength, Material.REDSTONE.toString());
+ }
+
+ @Command(hook = "ssm")
+ public boolean ssm(CommandSender sender, int strength, String material)
+ {
+ if (strength < 0 || strength > 15)
+ {
+ getLogger().message(sender, true, "The strength must be between 0 and 15!");
+ return true;
+ }
+
+ Player player = (Player) sender;
+ if (player.getGameMode() != GameMode.CREATIVE)
+ {
+ getLogger().message(sender, true, "You must be in creative mode to do that");
+ return true;
+ }
+
+ Material itemType = Material.matchMaterial(material);
+ if (itemType == null)
+ {
+ getLogger().message(sender, true, "The material " + material + " could not be recognized");
+ return true;
+ }
+
+ // Empty set in the first argument would make it always return the first block, because no block types are
+ // considered to be transparent. Only a value of null is treated as "air only".
+ Block targetBlock = player.getTargetBlock((Set<Material>) null, 5);
+ if (targetBlock == null)
+ {
+ getLogger().message(sender, true, "That command can only be used if a container is targeted!");
+ return true;
+ }
+ Inventory inventory = getInventory(targetBlock);
+ if (inventory == null)
+ {
+ getLogger().message(sender, true, "That command can only be used if a container is targeted!");
+ return true;
+ }
+
+ // --------Get the stack size and required amount of items to achieve the desired signal strength---------
+ int stackSize = itemType.getMaxStackSize();
+ int slotCount = inventory.getSize();
+ int itemCount = computeRequiredItemCount(strength, stackSize, slotCount);
+ if (itemCount == -1)
+ {
+ getLogger().message(sender, true,
+ "The desired signal strength could not be achieved with the requested item type");
+ return true;
+ }
+ // #--------Add the other side of the chest if target is a double chest and check if player can build---------
+ ArrayList<Block> containerBlocks = new ArrayList<>();
+ containerBlocks.add(targetBlock);
+
+ Material blockType = targetBlock.getType();
+ if (inventory.getType() == InventoryType.CHEST)
+ {
+ Arrays.stream(new BlockFace[] {BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST, BlockFace.NORTH})
+ .map(targetBlock::getRelative).filter(b -> b.getType() == blockType).forEach(containerBlocks::add);
+ }
+
+ for (Block containerBlock : containerBlocks)
+ {
+ if (!canBuild(player, containerBlock))
+ {
+ getLogger().message(sender, true, "You can not build here!");
+ return true;
+ }
+ }
+ // #----------------Insert items-------------
+ int fullStackCount = itemCount / stackSize;
+ int remaining = itemCount % stackSize;
+ for (Block containerBlock : containerBlocks)
+ {
+ // Below checks should evaluate to false, but let's be safe.
+ BlockState blockState = containerBlock.getState();
+ if (!(blockState instanceof InventoryHolder))
+ continue;
+
+ if (blockState instanceof Nameable && isSignalStrengthNameOrEmpty(((Nameable) blockState).getCustomName()))
+ {
+ ((Nameable) blockState).setCustomName(nameForSignalStrength(strength));
+ blockState.update();
+ }
+
+ Inventory inv = ((InventoryHolder) blockState).getInventory();
+ if (inv == null)
+ continue;
+
+ inv.clear();
+ for (int i = 0; i < fullStackCount; i++)
+ inv.setItem(i, new ItemStack(itemType, stackSize));
+ if (remaining > 0)
+ inv.setItem(fullStackCount, new ItemStack(itemType, remaining));
+
+ }
+ getLogger().message(sender, "Comparators attached to this " + enumNameToHumanName(blockType.name())
+ + " will now put out a signal strength of " + strength);
+ return true;
+ }
+
+ private static Inventory getInventory(Block b)
+ {
+ BlockState state = b.getState();
+ if (state instanceof InventoryHolder)
+ return ((InventoryHolder) state).getInventory();
+ return null;
+ }
+
+ private static int computeRequiredItemCount(int strength, int stackSize, int slotCount)
+ {
+ int itemCount = -1;
+ if (strength == 0)
+ itemCount = 0;
+ else if (strength == 1)
+ itemCount = 1;
+ else
+ itemCount = (int) Math.ceil(slotCount * stackSize / 14.0 * (strength - 1));
+
+ // Reverse engineer the calculation to verify
+ int resultingStrength = itemCount == 0 ? 0 : (int) Math.floor(1 + 14.0 * itemCount / stackSize / slotCount);
+ if (resultingStrength != strength)
+ {
+ return -1;
+ }
+ // Clarification on these formulas at https://minecraft.gamepedia.com/Redstone_Comparator#Containers
+ return itemCount;
+ }
+
+ private static boolean canBuild(Player p, Block b)
+ {
+ BlockPlaceEvent event = new BlockPlaceEvent(b, b.getState(), b.getRelative(BlockFace.DOWN),
+ p.getInventory().getItemInMainHand(), p, true, EquipmentSlot.HAND);
+ Bukkit.getPluginManager().callEvent(event);
+ return !event.isCancelled();
+ }
+
+ private static String enumNameToHumanName(String enumName)
+ {
+ return enumName.toLowerCase().replace('_', ' ');
+ }
+
+}
diff --git a/src/main/java/com/redstoner/modules/skullclick/SkullClick.java b/src/main/java/com/redstoner/modules/skullclick/SkullClick.java
new file mode 100644
index 0000000..d581d19
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/skullclick/SkullClick.java
@@ -0,0 +1,56 @@
+package com.redstoner.modules.skullclick;
+
+import org.bukkit.block.BlockState;
+import org.bukkit.block.Skull;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerInteractEvent;
+
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.None)
+@Version(major = 4, minor = 0, revision = 0, compatible = 4)
+@AutoRegisterListener
+public class SkullClick implements Module, Listener
+{
+ private boolean seen = false;
+
+ @SuppressWarnings("deprecation")
+ @EventHandler
+ public void onClick(PlayerInteractEvent e)
+ {
+ // The event gets fired twice, once for mainhand and once for offhand. This fixes that.
+ if (seen)
+ {
+ seen = false;
+ return;
+ }
+ seen = true;
+ if (e.getAction() == Action.RIGHT_CLICK_BLOCK && !e.isCancelled())
+ {
+ BlockState block = e.getClickedBlock().getState();
+ if (block instanceof Skull)
+ {
+ Skull skull = (Skull) block;
+ String owner = skull.getOwner();
+ if (owner == null || owner.equals(""))
+ {
+ getLogger().message(e.getPlayer(), true, "That skull has no owner.");
+ }
+ else
+ {
+ getLogger().message(e.getPlayer(), "That's " + owner + ".");
+ }
+ if (!e.getPlayer().isSneaking())
+ {
+ e.setCancelled(true);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/socialspy/Socialspy.cmd b/src/main/java/com/redstoner/modules/socialspy/Socialspy.cmd
new file mode 100644
index 0000000..32159b9
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/socialspy/Socialspy.cmd
@@ -0,0 +1,72 @@
+command socialspy {
+ format {
+ run config_format_show;
+ help Displays your current format;
+ }
+ format --default {
+ run config_format_default;
+ help Resets your format back to the default;
+ }
+ format --reset {
+ run config_format_default;
+ help Resets your format back to the default;
+ }
+ format [string:format...] {
+ run config_format format;
+ help Specifies your ss format. Use /socialspy format_help to get info about how the format works.;
+ }
+ format_help {
+ run format_help;
+ help Displays info about the format command;
+ }
+ prefix {
+ run config_prefix_default;
+ help Resets your color back to the default (light gray color code);
+ }
+ prefix [string:prefix] {
+ run config_prefix prefix;
+ help Sets your prefix to the specified term.;
+ }
+ commands list {
+ run commands_list;
+ help Displays all commands you're listening to.;
+ }
+ commands add [string:command] {
+ run commands_add command;
+ help Adds a command to the list of commands that you're listening to.;
+ }
+ commands del [string:command] {
+ run commands_del command;
+ help Deletes a command from the list of commands that you're listening to.;
+ }
+ stripcolor on {
+ run stripcolor_on;
+ }
+ stripcolor off {
+ run stripcolor_off;
+ }
+ stripcolor partial {
+ run stripcolor_partial;
+ }
+ stripcolor {
+ run stripcolor;
+ }
+ on {
+ run on;
+ type player;
+ }
+ off {
+ run off;
+ type player;
+ }
+ [empty] {
+ run toggle;
+ type player;
+ }
+ perm utils.socialspy;
+ migrate {
+ run migrate;
+ type console;
+ }
+ type all;
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/socialspy/Socialspy.java b/src/main/java/com/redstoner/modules/socialspy/Socialspy.java
new file mode 100644
index 0000000..e1caac9
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/socialspy/Socialspy.java
@@ -0,0 +1,377 @@
+package com.redstoner.modules.socialspy;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.json.simple.JSONArray;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.coremods.moduleLoader.ModuleLoader;
+import com.redstoner.misc.BroadcastFilter;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.CoreModule;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+import net.nemez.chatapi.click.Message;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 3, compatible = 4)
+public class Socialspy implements CoreModule
+{
+ @Command(hook = "config_prefix_default")
+ public boolean prefixDefault(CommandSender sender)
+ {
+ return prefix(sender, getDefaultPrefix());
+ }
+
+ @Command(hook = "config_prefix")
+ public boolean prefix(CommandSender sender, String prefix)
+ {
+ getLogger().message(sender, "Set your prefix to: " + prefix);
+ DataManager.setData(sender, "prefix", prefix);
+ return true;
+ }
+
+ @Command(hook = "config_format_default")
+ public boolean configFormatDefault(CommandSender sender)
+ {
+ return configFormat(sender, getDefaultFormat());
+ }
+
+ @Command(hook = "config_format_show")
+ public boolean configFormatShow(CommandSender sender)
+ {
+ String format = (String) DataManager.getOrDefault(sender, "format", getDefaultFormat());
+ getLogger().message(sender, "Your current format is: " + format.replaceAll("[&§]", "&&"));
+ return true;
+ }
+
+ @Command(hook = "config_format")
+ public boolean configFormat(CommandSender sender, String format)
+ {
+ getLogger().message(sender, "Set your format to: " + format);
+ DataManager.setData(sender, "format", format);
+ return true;
+ }
+
+ @Command(hook = "stripcolor_on")
+ public boolean stripcolorOn(CommandSender sender)
+ {
+ getLogger().message(sender, "Enabled stripping colors!");
+ DataManager.setData(sender, "stripcolor", "on");
+ return true;
+ }
+
+ @Command(hook = "stripcolor_off")
+ public boolean stripcolorOff(CommandSender sender)
+ {
+ getLogger().message(sender, "Disabled stripping colors!");
+ DataManager.setData(sender, "stripcolor", "off");
+ return true;
+ }
+
+ @Command(hook = "stripcolor_partial")
+ public boolean stripcolor_partial(CommandSender sender)
+ {
+ getLogger().message(sender, "Now replacing colors with their colorcode equivalent!");
+ DataManager.setData(sender, "stripcolor", "partial");
+ return true;
+ }
+
+ @Command(hook = "stripcolor")
+ public boolean stripcolor(CommandSender sender)
+ {
+ boolean b = DataManager.getOrDefault(sender, "stripcolor", "on").equals("on");
+ getLogger().message(sender, (b ? "Disabled" : "Enabled") + " stripping colors!");
+ DataManager.setData(sender, "stripcolor", !b);
+ return true;
+ }
+
+ @Command(hook = "on")
+ public boolean spyOn(CommandSender sender)
+ {
+ getLogger().message(sender, "Enabled socialspy!");
+ DataManager.setData(sender, "enabled", true);
+ return true;
+ }
+
+ @Command(hook = "off")
+ public boolean spyOff(CommandSender sender)
+ {
+ getLogger().message(sender, "Disabled socialspy!");
+ DataManager.setData(sender, "enabled", false);
+ return true;
+ }
+
+ @Command(hook = "toggle")
+ public boolean spyToggle(CommandSender sender)
+ {
+ boolean b = (boolean) DataManager.getOrDefault(sender, "enabled", false);
+ getLogger().message(sender, (b ? "Disabled" : "Enabled") + " socialspy!");
+ DataManager.setData(sender, "enabled", !b);
+ return true;
+ }
+
+ @Command(hook = "format_help")
+ public boolean formatInfo(CommandSender sender)
+ {
+ getLogger().message(sender,
+ new String[] {" Format placeholders:", " &c%s&eender &7(display name) | &c%S&eender &7(real name)",
+ " &c%t&earget &7(display name) | &c%T&earget &7(real name)",
+ " &c%p&erefix &7(see prefix option)", " &c%m&eessage", " &c%c&eommand",
+ " Any other text will be put as literal text. Use %% to escape any %.",
+ " The default format is: §e" + getDefaultFormat().replaceAll("(?i)&([0-9a-fl-o])", "&&$1"),
+ " The default prefix is: §e" + getDefaultPrefix().replaceAll("(?i)&([0-9a-fl-o])", "&&$1")});
+ return true;
+ }
+
+ @Command(hook = "commands_list")
+ public boolean commands_list(CommandSender sender)
+ {
+ ArrayList<String> message = new ArrayList<>();
+ JSONArray commands = (JSONArray) DataManager.getOrDefault(sender, "commands", getDefaultCommandList());
+ if (commands == null || commands.size() == 0)
+ message.add("You are not listening to any commands!");
+ else
+ {
+ message.add("You are listening to the following " + commands.size() + " commands:");
+ message.add(Arrays.toString(commands.toArray()).replace(", /", "&7, &e/").replace("[", "[&e").replace("]",
+ "&7]"));
+ }
+ getLogger().message(sender, message.toArray(new String[] {}));
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ private final JSONArray getDefaultCommandList()
+ {
+ JSONArray commands = new JSONArray();
+ commands.add("/m");
+ commands.add("/r");
+ return commands;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Command(hook = "commands_add")
+ public boolean commands_add(CommandSender sender, String command)
+ {
+ JSONArray commands = (JSONArray) DataManager.getOrDefault(sender, "commands", getDefaultCommandList());
+ commands.add(command);
+ DataManager.setData(sender, "commands", commands);
+ getLogger().message(sender, "You are now spying on &e" + command);
+ return true;
+ }
+
+ @Command(hook = "commands_del")
+ public boolean commands_del(CommandSender sender, String command)
+ {
+ JSONArray commands = (JSONArray) DataManager.getOrDefault(sender, "commands", getDefaultCommandList());
+ commands.remove(command);
+ DataManager.setData(sender, "commands", commands);
+ getLogger().message(sender, "You are no longer spying on &e" + command);
+ return true;
+ }
+
+ public static void spyBroadcast(CommandSender sender, CommandSender target, String message, String command,
+ BroadcastFilter filter)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("Socialspy");
+ Method m = mod.getClass().getDeclaredMethod("spyBroadcast_", CommandSender.class, CommandSender.class,
+ String.class, String.class, BroadcastFilter.class);
+ m.invoke(mod, sender, target, message, command, filter);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ public void spyBroadcast_(CommandSender sender, CommandSender target, String message, String command,
+ BroadcastFilter filter)
+ {
+ for (Player p : Bukkit.getOnlinePlayers())
+ {
+ if ((boolean) DataManager.getOrDefault(p, "enabled", false))
+ if (p.hasPermission("utils.socialspy"))
+ {
+ if (((JSONArray) DataManager.getOrDefault(p, "commands", getDefaultCommandList()))
+ .contains(command))
+ if (filter == null || filter.sendTo(p))
+ {
+ Message m = new Message(p, null);
+ m.appendText(formatMessage(p, sender, target, message, command));
+ m.send();
+ }
+ }
+ else
+ DataManager.setData(sender, "enabled", false);
+ }
+ if (((JSONArray) DataManager.getOrDefault(Bukkit.getConsoleSender(), "commands", getDefaultCommandList()))
+ .contains(command))
+ {
+ Message m = new Message(Bukkit.getConsoleSender(), null);
+ m.appendText(formatMessage(Bukkit.getConsoleSender(), sender, target, message, command));
+ m.send();
+ }
+ }
+
+ public static void spyBroadcast(CommandSender sender, String target, String message, String command,
+ BroadcastFilter filter)
+ {
+ try
+ {
+ Module mod = ModuleLoader.getModule("Socialspy");
+ Method m = mod.getClass().getDeclaredMethod("spyBroadcast_", CommandSender.class, String.class,
+ String.class, String.class, BroadcastFilter.class);
+ m.invoke(mod, sender, target, message, command, filter);
+ }
+ catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e)
+ {}
+ }
+
+ public void spyBroadcast_(CommandSender sender, String target, String message, String command,
+ BroadcastFilter filter)
+ {
+ for (Player p : Bukkit.getOnlinePlayers())
+ {
+ if ((boolean) DataManager.getOrDefault(p, "enabled", false))
+ if (p.hasPermission("utils.socialspy"))
+ {
+ if (((JSONArray) DataManager.getOrDefault(p, "commands", getDefaultCommandList()))
+ .contains(command))
+ if (filter == null || filter.sendTo(p))
+ {
+ Message m = new Message(p, null);
+ m.appendText(formatMessage(p, sender, target, message, command));
+ m.send();
+ }
+ }
+ else
+ DataManager.setData(sender, "enabled", false);
+ }
+ if (((JSONArray) DataManager.getOrDefault(Bukkit.getConsoleSender(), "commands", getDefaultCommandList()))
+ .contains(command))
+ {
+ Message m = new Message(Bukkit.getConsoleSender(), null);
+ m.appendText(formatMessage(Bukkit.getConsoleSender(), sender, target, message, command));
+ m.send();
+ }
+ }
+
+ private String formatMessage(CommandSender formatHolder, CommandSender sender, CommandSender target, String message,
+ String command)
+ {
+ String format = (String) DataManager.getOrDefault(formatHolder, "format", getDefaultFormat());
+ // Replace escaped % with placeholder
+ format = format.replace("%%", "§§");
+ // Sender name
+ format = format.replace("%s", Utils.getName(sender));
+ format = format.replace("%S", sender.getName());
+ // Target name
+ format = format.replace("%t", Utils.getName(target));
+ format = format.replace("%T", target.getName());
+ // Prefix
+ String prefix = (String) DataManager.getOrDefault(formatHolder, "prefix", getDefaultPrefix());
+ format = format.replace("%p", prefix);
+ // Apply colors to halfway replaced String
+ format = ChatColor.translateAlternateColorCodes('&', format);
+ // Insert command and message
+ format = format.replace("%c", command);
+
+ // Color stripping
+ Object o = DataManager.getOrDefault(formatHolder, "stripcolor", "off");
+ if (o instanceof Boolean)
+ {
+ boolean b = (boolean) o;
+ if (b)
+ o = "on";
+ else
+ o = "off";
+ DataManager.setData(formatHolder, "stripcolor", o);
+ }
+ String s = (String) o;
+ if (s.equals("on"))
+ message = ChatColor.stripColor(message).replaceAll("(?i)[&$][0-9a-fk-o]", "");
+ else if (s.equals("partial"))
+ message = message.replaceAll("(?i)[§&]([0-9a-fk-o])", "&&$1");
+ // Insert message
+ format = format.replace("%m", message);
+
+ // Convert placeholder back
+ format = format.replace("§§", "%");
+ return format;
+ }
+
+ private String formatMessage(CommandSender formatHolder, CommandSender sender, String target, String message,
+ String command)
+ {
+ String format = (String) DataManager.getOrDefault(formatHolder, "format", getDefaultFormat());
+ // Replace escaped % with placeholder
+ format = format.replace("%%", "§§");
+ // Sender name
+ format = format.replace("%s", Utils.getName(sender));
+ format = format.replace("%S", sender.getName());
+ // Target name
+ format = format.replace("%t", target);
+ format = format.replace("%T", target);
+ // Prefix
+ String prefix = (String) DataManager.getOrDefault(formatHolder, "prefix", getDefaultPrefix());
+ format = format.replace("%p", prefix);
+ // Apply colors to halfway replaced String
+ format = ChatColor.translateAlternateColorCodes('&', format);
+ // Insert command
+ format = format.replace("%c", command);
+
+ // Color stripping
+ Object o = DataManager.getOrDefault(formatHolder, "stripcolor", "off");
+ if (o instanceof Boolean)
+ {
+ boolean b = (boolean) o;
+ if (b)
+ o = "on";
+ else
+ o = "off";
+ DataManager.setData(formatHolder, "stripcolor", o);
+ }
+ String s = (String) o;
+ if (s.equals("on"))
+ message = ChatColor.stripColor(message).replaceAll("(?i)[&$][0-9a-fk-o]", "");
+ else if (s.equals("partial"))
+ message = message.replaceAll("(?i)[§&]([0-9a-fk-o])", "&&$1");
+ // Insert message
+ format = format.replace("%m", message);
+
+ // Convert placeholder back
+ format = format.replace("§§", "%");
+ return format;
+ }
+
+ private final String getDefaultFormat()
+ {
+ return " %s &7to %t%p: %m";
+ }
+
+ private final String getDefaultPrefix()
+ {
+ return "&7";
+ }
+
+ @Command(hook = "migrate")
+ public boolean migrate(CommandSender sender)
+ {
+ DataManager.migrateAll("Message");
+ return true;
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/tag/Tag.cmd b/src/main/java/com/redstoner/modules/tag/Tag.cmd
new file mode 100644
index 0000000..caa95ab
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/tag/Tag.cmd
@@ -0,0 +1,22 @@
+command tag {
+ add [string:player] [string:tag...] {
+ help Tags a player.;
+ run addtag player tag;
+ perm utils.tag;
+ }
+ del [string:player] [int:id] {
+ help Removes a tag.;
+ run deltag player id;
+ perm utils.tag;
+ }
+ check [string:player] {
+ help Lists all tags of a player.;\
+ run checktag player;
+ perm utils.tag;
+ }
+ [string:player] [string:tag...] {
+ help Tags a player.;
+ run addtag player tag;
+ perm utils.tag;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/tag/Tag.java b/src/main/java/com/redstoner/modules/tag/Tag.java
new file mode 100644
index 0000000..ae3302d
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/tag/Tag.java
@@ -0,0 +1,147 @@
+package com.redstoner.modules.tag;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.command.CommandSender;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.Command.AsyncType;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.JsonManager;
+import com.redstoner.misc.Main;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 1, compatible = 4)
+public class Tag implements Module
+{
+ private File tagLocation = new File(Main.plugin.getDataFolder(), "tag.json");
+ private JSONObject tags;
+
+ @Override
+ public boolean onEnable()
+ {
+ tags = JsonManager.getObject(tagLocation);
+ if (tags == null)
+ tags = new JSONObject();
+ return true;
+ }
+
+ @Override
+ public void onDisable()
+ {
+ saveTags();
+ }
+
+ @SuppressWarnings({"deprecation", "unchecked"})
+ @Command(hook = "addtag", async = AsyncType.ALWAYS)
+ public boolean addTag(CommandSender sender, String name, String tag)
+ {
+ OfflinePlayer player = Bukkit.getOfflinePlayer(name);
+ if (player == null)
+ {
+ getLogger().message(sender, true, "That player doesn't exist!");
+ return true;
+ }
+ UUID uuid = player.getUniqueId();
+ JSONArray tagArray;
+ if (tags.containsKey(uuid.toString()))
+ tagArray = (JSONArray) tags.get(uuid.toString());
+ else
+ tagArray = new JSONArray();
+ tagArray.add(tag);
+ if (!tags.containsKey(uuid.toString()))
+ tags.put(uuid.toString(), tagArray);
+ getLogger().message(sender, "Successfully added note &e" + tag + " &7to player &e" + name + "&7!");
+ saveTags();
+ return true;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Command(hook = "deltag", async = AsyncType.ALWAYS)
+ public boolean delTag(CommandSender sender, String name, int id)
+ {
+ if (id < 1)
+ {
+ getLogger().message(sender, true, "The ID you entered is too small, it must be at least 1!");
+ return true;
+ }
+ OfflinePlayer player = Bukkit.getOfflinePlayer(name);
+ if (player == null)
+ {
+ getLogger().message(sender, true, "That player doesn't exist!");
+ return true;
+ }
+ UUID uuid = player.getUniqueId();
+ if (!tags.containsKey(uuid.toString()))
+ {
+ getLogger().message(sender, true, "There are no notes about that player.");
+ return true;
+ }
+ JSONArray tagArray = (JSONArray) tags.get(uuid.toString());
+ int size = tagArray.size();
+ if (size == 0)
+ {
+ getLogger().message(sender, true, "There are no notes about that player.");
+ tags.remove(uuid.toString());
+ saveTags();
+ return true;
+ }
+ if (id > size)
+ {
+ getLogger().message(sender, true, "The number you entered is too big! It must be at most " + size + "!");
+ return true;
+ }
+ getLogger().message(sender, "Successfully removed note: &e" + tagArray.remove(id - 1));
+ if (tagArray.size() == 0)
+ tags.remove(uuid.toString());
+ saveTags();
+ return true;
+ }
+
+ @SuppressWarnings("deprecation")
+ @Command(hook = "checktag", async = AsyncType.ALWAYS)
+ public boolean checkTags(CommandSender sender, String name)
+ {
+ OfflinePlayer player = Bukkit.getOfflinePlayer(name);
+ if (player == null)
+ {
+ getLogger().message(sender, true, "That player doesn't exist!");
+ return true;
+ }
+ UUID uuid = player.getUniqueId();
+ if (!tags.containsKey(uuid.toString()))
+ {
+ getLogger().message(sender, "There are no notes about that player.");
+ return true;
+ }
+ JSONArray tagArray = (JSONArray) tags.get(uuid.toString());
+ int size = tagArray.size();
+ if (size == 0)
+ {
+ tags.remove(uuid.toString());
+ saveTags();
+ return true;
+ }
+ ArrayList<String> message = new ArrayList<String>();
+ message.add("There are &e" + size + "&7 notes about this player:");
+ for (int i = 0; i < size; i++)
+ message.add("&a" + (i + 1) + "&8: &e" + tagArray.get(i));
+ getLogger().message(sender, message.toArray(new String[] {}));
+ return true;
+ }
+
+ public void saveTags()
+ {
+ JsonManager.save(tags, tagLocation);
+ }
+
+}
diff --git a/src/main/java/com/redstoner/modules/teleport/Teleport.cmd b/src/main/java/com/redstoner/modules/teleport/Teleport.cmd
new file mode 100644
index 0000000..4e5930e
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/teleport/Teleport.cmd
@@ -0,0 +1,142 @@
+command teleport {
+ alias eteleport;
+ alias tp;
+ alias etp;
+ alias to;
+ alias eto;
+ alias tpo;
+ alias etpo;
+ alias tp2p;
+ alias etp2p;
+ [player:string] {
+ run tp player;
+ }
+ [player:string] [player2:string] {
+ run tp2 player player2;
+ }
+}
+
+command teleporthere {
+ alias eteleporthere;
+ alias tphere;
+ alias etphere;
+ alias tpohere;
+ alias etpohere;
+ [player:string] {
+ run tph player;
+ }
+}
+
+command teleportask {
+ alias eteleportask;
+ alias tpa;
+ alias etpa;
+ alias tpr;
+ alias etpr;
+ alias tpask;
+ alias etpask;
+ [player:string] {
+ run tpa player;
+ }
+}
+
+command teleportaskhere {
+ alias eteleportaskhere;
+ alias tpahere,
+ alias etpahere;
+ alias tprhere;
+ alias etrphere;
+ alias tpaskhere;
+ alias etpaskhere;
+ [player:string] {
+ run tpah player;
+ help ask another player to teleport to you.;
+ }
+}
+
+command tpall {
+ alias etpall;
+ [empty] {
+ run tpall;
+ help Teleports everyone to you.;
+ }
+ [player] {
+ run tpall2 player;
+ help Teleports everyone to the specified player.;
+ }
+ perm utils.admin.teleport;
+}
+
+command tpaall {
+ alias etpall;
+ [empty] {
+ run tpaall;
+ help Sends a tpa request to every player.;
+ perm utils.admin.teleport;
+ }
+ [player:string] {
+ run tpaall2 player;
+ help Sends a tpa request to every player.;
+ }
+ perm utils.admin.teleport;
+}
+
+command tpaccept {
+ alias etpaccept;
+ alias tpyes;
+ alias etpyes;
+ [empty] {
+ run tpaccept;
+ help Accepts the latest pending tpa request.;
+ }
+ [index:int] {
+ run tpaccept2 index;
+ help Accepts the specified pending tpa request.;
+ }
+ perm utils.teleport.request;
+}
+
+command tpacancel {
+ alias etpacencel;
+ [empty] {
+ run tpacancel;
+ help Cancels an outgoing pending tpa request.;
+ perm utils.teleport.request;
+ }
+}
+
+command tpdeny {
+ alias etpdeny;
+ alias tpno;
+ alias etpno;
+ perm utils.teleport.request;
+ [empty] {
+ run tpdeny;
+ }
+ [index:int] {
+ run tpdeny2 index;
+ }
+}
+
+command tplist {
+ alias etplist;
+ alias tpl;
+ alias etpl;
+ [empty] {
+ run tpl;
+ }
+}
+
+command tptoggle {
+ alias etptoggle;
+ [status:string] {
+ run tptoggle status;
+ help sets your tpa status;
+ perm utils.teleport.toggle;
+ }
+ [command:string] [status:string] {
+ run tptoggle2 command status;
+ help sets your tpa status for only one command (e.g. tpa/tpahere).;
+ perm utils.teleport.toggle;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/teleport/Teleport.java b/src/main/java/com/redstoner/modules/teleport/Teleport.java
new file mode 100644
index 0000000..7680852
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/teleport/Teleport.java
@@ -0,0 +1,185 @@
+package com.redstoner.modules.teleport;
+
+import java.util.ArrayList;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+import net.nemez.chatapi.click.Message;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 0, revision = 0, compatible = 4)
+public class Teleport implements Module
+{
+ public static final String PERMISSION_TELEPORT = "utils.admin.teleport";
+
+ public ArrayList<TPRequest> pending_requests;
+
+ @Override
+ public void postEnable()
+ {
+ pending_requests = new ArrayList<TPRequest>();
+ }
+
+ @Command(hook = "tp")
+ public boolean teleport(CommandSender sender, String player)
+ {
+ if (!sender.hasPermission(PERMISSION_TELEPORT))
+ return tpa(sender, player);
+ return true;
+ }
+
+ @Command(hook = "tp2")
+ public boolean teleport(CommandSender sender, String player, String player2)
+ {
+ if (!sender.hasPermission(PERMISSION_TELEPORT))
+ if (player2.equals(((Player) sender).getName()))
+ return tpahere(sender, player);
+ else
+ {
+ getLogger().message(sender, "You do not have the required permissions to run that Command!");
+ return true;
+ }
+ Player p1 = Bukkit.getPlayer(player);
+ Player p2 = Bukkit.getPlayer(player2);
+ if (p1 == null || p2 == null)
+ {
+ getLogger().message(sender, true, "The specified player couldn't be found!");
+ return true;
+ }
+ p1.teleport(p2);
+ getLogger().message(p1, "You have been teleported to: " + p2.getDisplayName());
+ if (!sender.getName().equals(p1.getName()))
+ getLogger().message(sender,
+ p1.getDisplayName() + "&7 has been teleported to " + p2.getDisplayName() + "&7!");
+ return true;
+ }
+
+ @Command(hook = "tpa")
+ public boolean tpa(CommandSender sender, String player)
+ {
+ return true;
+ }
+
+ @Command(hook = "tpahere")
+ public boolean tpahere(CommandSender sender, String player)
+ {
+ return true;
+ }
+
+ @Command(hook = "tpmenu")
+ public boolean tpinventory(CommandSender sender)
+ {
+
+ return true;
+ }
+
+ protected void remove(TPRequest request)
+ {
+
+ }
+}
+
+class TPRequest implements Runnable
+{
+ private final Teleport holder;
+ private final Player sender;
+ private final Player target;
+ private final Type type;
+ private int index;
+
+ Thread t;
+
+ public TPRequest(Player sender, Player target, Type type, int index, Teleport holder)
+ {
+ this.sender = sender;
+ this.target = target;
+ this.type = type;
+ this.index = 0;
+ this.holder = holder;
+ }
+
+ public Player getSender()
+ {
+ return sender;
+ }
+
+ public Player getTarget()
+ {
+ return target;
+ }
+
+ public Type getType()
+ {
+ return type;
+ }
+
+ public int getIndex()
+ {
+ return index;
+ }
+
+ public void setIndex(int index)
+ {
+ this.index = index;
+ }
+
+ public void execute()
+ {
+ switch (type)
+ {
+ case tpa:
+ sender.teleport(target);
+ break;
+ case tpahere:
+ target.teleport(sender);
+ break;
+ }
+ }
+
+ public void abort()
+ {
+ t.interrupt();
+ }
+
+ @Override
+ public void run()
+ {
+ t = Thread.currentThread();
+ try
+ {
+ Thread.sleep(60000);
+ }
+ catch (InterruptedException e)
+ {
+ holder.remove(this);
+ Message m = new Message(sender, null);
+ if (DataManager.getState(sender, "AFK"))
+ {
+ m.appendText(target.getDisplayName() + " is AFK and might not respond. ");
+ m.appendSendChat("Try again?", "/" + type.toString() + " " + target.getName());
+ }
+ if (DataManager.getState(sender, "BUSY"))
+ {
+ m.appendText(target.getDisplayName() + " is BUSY and might not respond. ");
+ m.appendSendChat("Try again?", "/" + type.toString() + " " + target.getName());
+ }
+ return;
+ }
+ holder.remove(this);
+ }
+}
+
+enum Type
+{
+ tpa,
+ tpahere;
+}
diff --git a/src/main/java/com/redstoner/modules/tilechunks/LaggyTileChunk.java b/src/main/java/com/redstoner/modules/tilechunks/LaggyTileChunk.java
new file mode 100644
index 0000000..e2456d3
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/tilechunks/LaggyTileChunk.java
@@ -0,0 +1,21 @@
+package com.redstoner.modules.tilechunks;
+
+import org.bukkit.Location;
+import org.bukkit.World;
+
+public class LaggyTileChunk {
+ public final int x, y, z, amount;
+ public final World world;
+
+ public LaggyTileChunk(int x, int y, int z, World world, int amount) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.world = world;
+ this.amount = amount;
+ }
+
+ public Location getLocation() {
+ return new Location(world, x, y, z);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/tilechunks/TileChunks.cmd b/src/main/java/com/redstoner/modules/tilechunks/TileChunks.cmd
new file mode 100644
index 0000000..c0e0773
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/tilechunks/TileChunks.cmd
@@ -0,0 +1,19 @@
+command lct {
+ perm utils.tilechunks;
+
+ list {
+ run list_cmd;
+ help re-lists already scanned chunks;
+ }
+
+ [int:amount] {
+ run scan_cmd amount;
+ help scans for laggy chunks;
+ }
+
+ tp [int:number] {
+ run tp number;
+ help teleports to the specified chunk;
+ type player;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/tilechunks/TileChunks.java b/src/main/java/com/redstoner/modules/tilechunks/TileChunks.java
new file mode 100644
index 0000000..75a3fd2
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/tilechunks/TileChunks.java
@@ -0,0 +1,83 @@
+package com.redstoner.modules.tilechunks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
+import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.Command.AsyncType;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class TileChunks implements Module
+{
+ private List<LaggyTileChunk> laggyChunks = new ArrayList<>();
+
+ private void scan(int amount)
+ {
+ laggyChunks.clear();
+ for (World world : Bukkit.getServer().getWorlds())
+ {
+ for (Chunk chunk : world.getLoadedChunks())
+ {
+ int amount2 = chunk.getTileEntities().length;
+ if (amount2 > amount)
+ {
+ Location entLoc = chunk.getTileEntities()[0].getLocation();
+ laggyChunks.add(new LaggyTileChunk(entLoc.getBlockX(), entLoc.getBlockY(), entLoc.getBlockZ(),
+ world, amount2));
+ }
+ }
+ }
+ }
+
+ @Command(hook = "list_cmd")
+ public void list(CommandSender sender)
+ {
+ if (laggyChunks.size() > 0)
+ {
+ ArrayList<String> message = new ArrayList<>();
+ for (LaggyTileChunk lc : laggyChunks)
+ {
+ message.add("§b[§a" + laggyChunks.indexOf(lc) + "§b]: §a" + lc.x + "§7, §a" + lc.y + "§7, §a" + lc.z
+ + " §7(" + lc.world.getName() + ") §a- §b" + lc.amount + " tile entities");
+ }
+ message.add("§2-------------------");
+ getLogger().message(sender, message.toArray(new String[] {}));
+ }
+ else
+ getLogger().message(sender, true, "Couldn't find any chunks with that many tile entities.");
+ }
+
+ @Command(hook = "scan_cmd", async = AsyncType.ALWAYS)
+ public void scan_cmd(CommandSender sender, int amount)
+ {
+ scan(amount);
+ list(sender);
+ }
+
+ @Command(hook = "tp")
+ public void tp(CommandSender sender, int number)
+ {
+ Player player = (Player) sender;
+ if (number < laggyChunks.size())
+ {
+ player.teleport(laggyChunks.get(number).getLocation());
+ getLogger().message(player, "§aTeleported to chunk " + number + "!");
+ }
+ else
+ {
+ getLogger().message(sender, true, "§4Invalid chunk number! Use §e/lc list §4to show laggy chunks!");
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/vanish/Vanish.cmd b/src/main/java/com/redstoner/modules/vanish/Vanish.cmd
new file mode 100644
index 0000000..618a4c1
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/vanish/Vanish.cmd
@@ -0,0 +1,33 @@
+command vanish {
+ [empty] {
+ help Toggles your vanish status.;
+ type player;
+ run vanish;
+ perm utils.vanish;
+ }
+ on {
+ help Turns your vanish on.;
+ type player;
+ run vanish_on;
+ perm utils.vanish;
+ }
+ off {
+ help Turns your vanish off.;
+ type player;
+ run vanish_off;
+ perm utils.vanish;
+ }
+ [string:name] {
+ help Toggles someone elses vanish;
+ run vanish_other name;
+ perm utils.vanishother;
+ }
+}
+command imout {
+ [empty] {
+ help Makes you magically disappear;
+ type player;
+ perm utils.imout;
+ run imout;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/vanish/Vanish.java b/src/main/java/com/redstoner/modules/vanish/Vanish.java
new file mode 100644
index 0000000..d4e57e8
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/vanish/Vanish.java
@@ -0,0 +1,260 @@
+package com.redstoner.modules.vanish;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+import com.redstoner.modules.datamanager.DataManager;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Vanish implements Module, Listener
+{
+ private ArrayList<UUID> vanished = new ArrayList<>();
+ List<String> imouted = new ArrayList<String>();
+ private HashMap<UUID, ArrayList<UUID>> vanishOthers = new HashMap<>();
+
+ @Override
+ public void migrate(Version old)
+ {
+ Module.super.migrate(old);
+ if ((old.major() == 4) && (old.minor() == 0) && (old.revision() <= 1))
+ {
+ DataManager.setConfig("indicator", "&7[V]");
+ }
+ }
+
+ @Command(hook = "vanish")
+ public boolean vanish(CommandSender sender)
+ {
+ UUID uid = ((Player) sender).getUniqueId();
+ if (vanished.contains(uid))
+ {
+ vanished.remove(uid);
+ getLogger().message(sender, "You are no longer vanished!");
+ unvanishPlayer((Player) sender);
+ }
+ else
+ {
+ vanished.add(uid);
+ getLogger().message(sender, "You are now vanished!");
+ vanishPlayer((Player) sender);
+ }
+ return true;
+ }
+
+ @Command(hook = "vanish_on")
+ public boolean vanishOn(CommandSender sender)
+ {
+ UUID uid = ((Player) sender).getUniqueId();
+ if (vanished.contains(uid))
+ getLogger().message(sender,
+ "You were already vanished, however we refreshed the vanish for you just to be sure!");
+ else
+ {
+ vanished.add(uid);
+ getLogger().message(sender, "You are now vanished!");
+ }
+ vanishPlayer((Player) sender);
+ return true;
+ }
+
+ @Command(hook = "vanish_off")
+ public boolean vanishOff(CommandSender sender)
+ {
+ UUID uid = ((Player) sender).getUniqueId();
+ if (!vanished.contains(uid))
+ getLogger().message(sender,
+ "You were not vanished, however we refreshed the vanish for you just to be sure!");
+ else
+ {
+ vanished.remove(uid);
+ getLogger().message(sender, "You are no longer vanished!");
+ }
+ unvanishPlayer((Player) sender);
+ return true;
+ }
+
+ @Command(hook = "vanish_other")
+ public boolean vanishOther(CommandSender sender, String name)
+ {
+ Player player = Bukkit.getPlayer(name);
+ if (player == null)
+ {
+ getLogger().message(sender, "&cPlayer &6" + name + " &ccould not be found!");
+ return true;
+ }
+ UUID uid = player.getUniqueId();
+ if (player.hasPermission("utils.vanish"))
+ {
+ if (vanished.contains(uid))
+ {
+ vanished.remove(uid);
+ getLogger().message(sender, "Successfully unvanished &e" + player.getDisplayName());
+ getLogger().message(player, "You are no longer vanished!");
+ }
+ else
+ {
+ vanished.add(uid);
+ getLogger().message(sender, "Successfully vanished &e" + player.getDisplayName());
+ getLogger().message(player, "You are now vanished!");
+ }
+ return true;
+ }
+ for (Entry<UUID, ArrayList<UUID>> entry : vanishOthers.entrySet())
+ {
+ if (entry.getValue().contains(uid))
+ {
+ entry.getValue().remove(uid);
+ getLogger().message(sender, "Successfully unvanished &e" + player.getDisplayName());
+ getLogger().message(player, "You are no longer vanished!");
+ if (entry.getValue().size() == 0)
+ vanishOthers.remove(entry.getKey());
+ return true;
+ }
+ }
+ UUID uuid = ((Player) sender).getUniqueId();
+ ArrayList<UUID> toAddTo = vanishOthers.get(uuid);
+ if (toAddTo == null)
+ toAddTo = new ArrayList<>();
+ toAddTo.add(uid);
+ vanishOthers.put(uuid, toAddTo);
+ getLogger().message(sender, "Successfully vanished &e" + player.getDisplayName());
+ getLogger().message(player, "You are now vanished!");
+ return true;
+ }
+
+ @SuppressWarnings("deprecation")
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onPlayerJoin(PlayerJoinEvent event)
+ {
+ Player player = event.getPlayer();
+ DataManager.setState(player, "vanished", vanished.contains(player.getUniqueId()));
+ if (vanished.contains(player.getUniqueId()))
+ {
+ for (Player p : Bukkit.getOnlinePlayers())
+ {
+ if (!p.hasPermission("utils.vanish"))
+ p.hidePlayer(player);
+ }
+ event.setJoinMessage(null);
+ }
+ if (player.hasPermission("utils.vanish"))
+ return;
+ for (UUID uid : vanished)
+ {
+ Player p = Bukkit.getPlayer(uid);
+ if (p == null)
+ continue;
+ player.hidePlayer(p);
+ }
+ for (Entry<UUID, ArrayList<UUID>> entry : vanishOthers.entrySet())
+ {
+ for (UUID uid : entry.getValue())
+ {
+ Player p = Bukkit.getPlayer(uid);
+ if (p == null)
+ continue;
+ player.hidePlayer(p);
+ }
+ }
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onPlayerLeave(PlayerQuitEvent event)
+ {
+ Player player = event.getPlayer();
+ UUID uid = player.getUniqueId();
+ if (vanished.contains(player.getUniqueId()))
+ {
+ event.setQuitMessage(null);
+ }
+ if (vanishOthers.containsKey(uid))
+ {
+ ArrayList<UUID> toUnvanish = vanishOthers.remove(uid);
+ for (UUID uuid : toUnvanish)
+ {
+ Player p = Bukkit.getPlayer(uuid);
+ if (p != null)
+ unvanishPlayer(p);
+ }
+ }
+ boolean wasVanished = false;
+ for (Entry<UUID, ArrayList<UUID>> entry : vanishOthers.entrySet())
+ {
+ if (entry.getValue().contains(uid))
+ {
+ entry.getValue().remove(uid);
+ wasVanished = true;
+ break;
+ }
+ }
+ if (wasVanished)
+ unvanishPlayer(player);
+ }
+
+ @SuppressWarnings("deprecation")
+ private void vanishPlayer(Player player)
+ {
+ for (Player p : Bukkit.getOnlinePlayers())
+ {
+ if (!p.hasPermission("utils.vanish"))
+ p.hidePlayer(player);
+ }
+ DataManager.setState(player, "vanished", true);
+ DataManager.setData(Utils.getID(player), "Seen", "lastquit", System.currentTimeMillis());
+ }
+
+ @SuppressWarnings("deprecation")
+ private void unvanishPlayer(Player player)
+ {
+ for (Player p : Bukkit.getOnlinePlayers())
+ p.showPlayer(player);
+ DataManager.setState(player, "vanished", false);
+ DataManager.setData(Utils.getID(player), "Seen", "lastjoined", System.currentTimeMillis());
+ }
+
+ @Command(hook = "imout")
+ public void onImoutCommand(CommandSender sender)
+ {
+ String symbol;
+ Player s = (Player) sender;
+ String name = sender.getName();
+ if (imouted.contains(name))
+ {
+ symbol = "§a§l+";
+ getLogger().message(sender, "§eWelcome back! You are no longer hidden", "");
+ s.performCommand("vanish off");
+ s.performCommand("act off");
+ imouted.remove(name);
+ }
+ else
+ {
+ symbol = "§c§l-";
+ getLogger().message(sender, "§e§oPoof!§e You are now gone!", "");
+ s.performCommand("vanish on");
+ s.performCommand("act on");
+ imouted.add(name);
+ }
+ Utils.broadcast(symbol, " §7" + name, null);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/warn/Warn.cmd b/src/main/java/com/redstoner/modules/warn/Warn.cmd
new file mode 100644
index 0000000..5021e0f
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/warn/Warn.cmd
@@ -0,0 +1,15 @@
+command warn {
+ [empty] {
+ run warn;
+ help Warns other players about definite lag;
+ perm utils.warn;
+ }
+}
+
+command warnp {
+ [empty] {
+ run warnp;
+ help Warns other players about possible lag;
+ perm utils.warn;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/warn/Warn.java b/src/main/java/com/redstoner/modules/warn/Warn.java
new file mode 100644
index 0000000..c272c67
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/warn/Warn.java
@@ -0,0 +1,29 @@
+package com.redstoner.modules.warn;
+
+import org.bukkit.command.CommandSender;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Utils;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class Warn implements Module
+{
+ @Command(hook = "warn")
+ public void warn_normal(CommandSender sender)
+ {
+ String name = Utils.getName(sender);
+ Utils.broadcast(null, "§2Lag incoming! - §9" + name, null);
+ }
+
+ @Command(hook = "warnp")
+ public void warn_possible(CommandSender sender)
+ {
+ String name = Utils.getName(sender);
+ Utils.broadcast(null, "§2Possible lag incoming! - §9" + name, null);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/webtoken/WebToken.cmd b/src/main/java/com/redstoner/modules/webtoken/WebToken.cmd
new file mode 100644
index 0000000..898d212
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/webtoken/WebToken.cmd
@@ -0,0 +1,21 @@
+command token {
+ perm utils.webtoken;
+
+ [empty] {
+ help Displays an already generated token;
+ type player;
+ perm utils.webtoken;
+ run token;
+ }
+}
+
+command gettoken {
+ perm utils.webtoken;
+
+ [string:email...] {
+ help Generates a token used for website authentication;
+ type player;
+ perm utils.webtoken;
+ run gettoken email;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/webtoken/WebToken.java b/src/main/java/com/redstoner/modules/webtoken/WebToken.java
new file mode 100644
index 0000000..6a4a8b0
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/webtoken/WebToken.java
@@ -0,0 +1,225 @@
+package com.redstoner.modules.webtoken;
+
+import java.io.IOException;
+import java.util.Random;
+import java.util.UUID;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.json.simple.parser.ParseException;
+
+import com.nemez.cmdmgr.Command;
+import com.nemez.cmdmgr.Command.AsyncType;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.mysql.Config;
+import com.redstoner.misc.mysql.MysqlHandler;
+import com.redstoner.misc.mysql.elements.ConstraintOperator;
+import com.redstoner.misc.mysql.elements.MysqlConstraint;
+import com.redstoner.misc.mysql.elements.MysqlDatabase;
+import com.redstoner.misc.mysql.elements.MysqlTable;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class WebToken implements Module
+{
+ private static final int TOKEN_LENGTH = 6;
+ private static final String CONSONANTS = "bcdfghjklmnpqrstvwxyz";
+ private static final String VOWELS = "aeiou";
+ private MysqlTable table;
+
+ @Override
+ public boolean onEnable()
+ {
+ Config config;
+ try
+ {
+ config = Config.getConfig("WebToken.json");
+ }
+ catch (IOException | ParseException e1)
+ {
+ e1.printStackTrace();
+ return false;
+ }
+ if (config == null || !config.containsKey("database") || !config.containsKey("table"))
+ {
+ getLogger().error("Could not load the WebToken config file, disabling!");
+ config.put("database", "redstoner");
+ config.put("table", "webtoken");
+ return false;
+ }
+ try
+ {
+ MysqlDatabase database = MysqlHandler.INSTANCE.getDatabase(config.get("database") + "?autoReconnect=true");
+ table = database.getTable(config.get("table"));
+ }
+ catch (NullPointerException e)
+ {
+ getLogger().error("Could not use the WebToken config, aborting!");
+ return false;
+ }
+ return true;
+ }
+
+ private String getNextId() throws Exception
+ {
+ Object[] results = table.get("select id from register_tokens order by id desc limit 1;");
+ if (results[0] instanceof Integer)
+ {
+ return ((int) results[0]) + 1 + "";
+ }
+ else if (results[0] instanceof String)
+ {
+ int id = Integer.valueOf((String) results[0]);
+ return id + 1 + "";
+ }
+ else
+ {
+ throw new Exception("Token query returned invalid result!");
+ }
+ }
+
+ private String query(String emailOrToken, UUID uuid) throws Exception
+ {
+ if (!(emailOrToken.equals("token") && emailOrToken.equals("email")))
+ {
+ throw new Exception("Invalid database query: " + emailOrToken);
+ }
+ Object[] results = table.get(emailOrToken,
+ new MysqlConstraint("uuid", ConstraintOperator.EQUAL, uuid.toString().replaceAll("-", "")));
+ if (results instanceof String[])
+ {
+ String[] tokenResults = (String[]) results;
+ if (tokenResults.length == 1)
+ {
+ return tokenResults[0];
+ }
+ else
+ {
+ return null;
+ }
+ }
+ else
+ {
+ throw new Exception("Token query returned invalid result!");
+ }
+ }
+
+ private boolean match(String string, String regex)
+ {
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(string);
+ return matcher.find();
+ }
+
+ private void printToken(Player player, String email, String token)
+ {
+ String[] message = new String[] {"&aEmail: " + email, "&aToken: " + token,
+ "&cIMPORTANT: never share the token with anyone!", "&cIt could be used to claim your website account!"};
+ getLogger().message(player, message);
+ }
+
+ private String generateToken()
+ {
+ String token = "";
+ Random random = new Random();
+ int start = random.nextInt(2);
+ for (int i = 0; i < TOKEN_LENGTH; i++)
+ {
+ if (i % 2 == start)
+ {
+ token += CONSONANTS.charAt(random.nextInt(21));
+ }
+ else
+ {
+ token += VOWELS.charAt(random.nextInt(5));
+ }
+ }
+ return token;
+ }
+
+ @Command(hook = "token", async = AsyncType.ALWAYS)
+ public void token(CommandSender sender)
+ {
+ Player player = (Player) sender;
+ UUID uuid = player.getUniqueId();
+ try
+ {
+ String token = query("token", uuid);
+ if (token == null)
+ {
+ getLogger().message(player, true, "You don't have a token yet! Use &e/gettoken <email>&7 to get one.");
+ }
+ else
+ {
+ String email = query("email", uuid);
+ printToken(player, email, token);
+ }
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ Thread.sleep(100);
+ String token = query("token", uuid);
+ if (token == null)
+ {
+ getLogger().message(player, true,
+ "You don't have a token yet! Use &e/gettoken <email>&7 to get one.");
+ }
+ else
+ {
+ String email = query("email", uuid);
+ printToken(player, email, token);
+ }
+ }
+ catch (Exception e2)
+ {
+ getLogger().message(player, true, "Error getting your token, please contact an admin!");
+ e2.printStackTrace();
+ }
+ }
+ }
+
+ @Command(hook = "gettoken", async = AsyncType.ALWAYS)
+ public void token(CommandSender sender, String email)
+ {
+ Player player = (Player) sender;
+ if (match(email, "^.+@(.+\\..{2,}|\\[[0-9a-fA-F:.]+\\])$"))
+ {
+ String uuid = player.getUniqueId().toString().replaceAll("-", "");
+ String token = generateToken();
+ try
+ {
+ String id = getNextId();
+ table.delete(new MysqlConstraint("uuid", ConstraintOperator.EQUAL, uuid));
+ table.insert(id, uuid, token, email);
+ printToken(player, email, token);
+ }
+ catch (Exception e)
+ {
+ try
+ {
+ Thread.sleep(100);
+ String id = getNextId();
+ table.delete(new MysqlConstraint("uuid", ConstraintOperator.EQUAL, uuid));
+ table.insert(id, uuid, token, email);
+ printToken(player, email, token);
+ }
+ catch (Exception e2)
+ {
+ getLogger().message(player, true, "Error getting your token, please contact an admin!");
+ e.printStackTrace();
+ }
+ }
+ }
+ else
+ {
+ getLogger().message(player, true, "Hmm... That doesn't look like a valid email!");
+ }
+ }
+}
diff --git a/src/main/java/com/redstoner/utils/CommandException.java b/src/main/java/com/redstoner/utils/CommandException.java
new file mode 100644
index 0000000..0b12125
--- /dev/null
+++ b/src/main/java/com/redstoner/utils/CommandException.java
@@ -0,0 +1,29 @@
+package com.redstoner.utils;
+
+public class CommandException extends Exception
+{
+ private static final long serialVersionUID = -7176634557736106754L;
+
+ public CommandException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ public CommandException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public CommandException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)
+ {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+ public CommandException()
+ {}
+
+ public CommandException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/src/main/java/com/redstoner/utils/CommandMap.java b/src/main/java/com/redstoner/utils/CommandMap.java
new file mode 100644
index 0000000..4003b01
--- /dev/null
+++ b/src/main/java/com/redstoner/utils/CommandMap.java
@@ -0,0 +1,23 @@
+package com.redstoner.utils;
+
+import java.lang.reflect.Field;
+import java.util.Map;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.Command;
+import org.bukkit.command.SimpleCommandMap;
+import org.bukkit.plugin.SimplePluginManager;
+
+public class CommandMap
+{
+ @SuppressWarnings("unchecked")
+ public static Map<String, Command> getCommandMap() throws ReflectiveOperationException, ClassCastException
+ {
+ Field field = SimplePluginManager.class.getDeclaredField("commandMap");
+ field.setAccessible(true);
+ Object map = field.get(Bukkit.getPluginManager());
+ field = SimpleCommandMap.class.getDeclaredField("knownCommands");
+ field.setAccessible(true);
+ return (Map<String, Command>) field.get(map);
+ }
+}
diff --git a/src/main/java/com/redstoner/utils/ItemProperties.java b/src/main/java/com/redstoner/utils/ItemProperties.java
new file mode 100644
index 0000000..cddd0a4
--- /dev/null
+++ b/src/main/java/com/redstoner/utils/ItemProperties.java
@@ -0,0 +1,272 @@
+package com.redstoner.utils;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.BiConsumer;
+
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+/** Save and load {@link ItemStack} in json format
+ * Any additional NBT data not included by {@link ItemMeta} is discarded. */
+public class ItemProperties
+{
+ private int id = 0;
+ private byte data = 0;
+ private int amount = 1;
+ private Map<Enchantment, Integer> enchantments;
+ private List<String> lore;
+ private String displayName;
+ private boolean unbreakable = false;
+
+ public ItemProperties()
+ {}
+
+ @SuppressWarnings("deprecation")
+ public ItemProperties(ItemStack item)
+ {
+ if (item == null)
+ return;
+ id = item.getTypeId();
+ data = item.getData().getData();
+ amount = item.getAmount();
+ enchantments = new HashMap<>();
+ ItemMeta meta = item.getItemMeta();
+ if (meta == null)
+ return;
+ if (meta.hasEnchants())
+ {
+ enchantments.putAll(meta.getEnchants());
+ }
+ if (meta.hasLore())
+ {
+ lore = meta.getLore();
+ }
+ if (meta.hasDisplayName())
+ {
+ displayName = meta.getDisplayName();
+ }
+ unbreakable = meta.isUnbreakable();
+ }
+
+ @SuppressWarnings("deprecation")
+ public ItemStack toItemStack()
+ {
+ ItemStack result = new ItemStack(id, amount, data);
+ ItemMeta meta = result.getItemMeta();
+ if (meta == null)
+ return result;
+ if (enchantments != null)
+ {
+ enchantments.forEach(new BiConsumer<Enchantment, Integer>()
+ {
+ @Override
+ public void accept(Enchantment ench, Integer level)
+ {
+ meta.addEnchant(ench, level, true);
+ }
+ });
+ }
+ if (lore != null)
+ {
+ meta.setLore(lore);
+ }
+ if (displayName != null)
+ {
+ meta.setDisplayName(displayName);
+ }
+ meta.setUnbreakable(unbreakable);
+ result.setItemMeta(meta);
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ public JSONObject toJSONObject()
+ {
+ JSONObject object = new JSONObject();
+ object.put("id", id + "");
+ object.put("data", data + "");
+ object.put("amount", amount + "");
+ if (displayName != null)
+ {
+ object.put("displayName", displayName);
+ }
+ if (enchantments != null)
+ {
+ Map<Enchantment, Integer> enchantments = this.enchantments;
+ JSONObject stringKeys = new JSONObject();
+ for (Map.Entry<Enchantment, Integer> entry : enchantments.entrySet())
+ {
+ stringKeys.put(entry.getKey().getName(), entry.getValue());
+ }
+ object.put("enchantments", stringKeys);
+ }
+ if (lore != null)
+ {
+ object.put("lore", JSONArray.toJSONString(lore));
+ }
+ if (unbreakable)
+ {
+ object.put("unbreakable", true);
+ }
+ return object;
+ }
+
+ @Override
+ public String toString()
+ {
+ return toJSONObject().toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ public ItemProperties loadFrom(JSONObject object)
+ {
+ for (Object obj : object.entrySet())
+ {
+ Entry<String, Object> entry = (Entry<String, Object>) obj;
+ final String key = entry.getKey();
+ switch (key)
+ {
+ case "id":
+ id = Integer.parseInt((String) entry.getValue());
+ break;
+ case "data":
+ data = Byte.parseByte((String) entry.getValue());
+ break;
+ case "amount":
+ amount = Integer.parseInt((String) entry.getValue());
+ break;
+ case "unbreakable":
+ unbreakable = (boolean) entry.getValue();
+ break;
+ case "enchantments":
+ {
+ if (enchantments == null)
+ {
+ enchantments = new HashMap<>();
+ }
+ else if (!enchantments.isEmpty())
+ {
+ enchantments.clear();
+ }
+ JSONObject read = (JSONObject) entry.getValue();
+ if (read != null)
+ {
+ for (Object obj2 : read.entrySet())
+ {
+ Entry<String, Integer> entry2 = (Entry<String, Integer>) obj2;
+ Enchantment ench = Enchantment.getByName(entry2.getKey());
+ if (ench != null)
+ {
+ enchantments.put(ench, entry2.getValue());
+ }
+ }
+ }
+ break;
+ }
+ case "lore":
+ JSONParser parser = new JSONParser();
+ Object rawObject;
+ try
+ {
+ rawObject = parser.parse((String) entry.getValue());
+ }
+ catch (ParseException e)
+ {
+ rawObject = new JSONArray();
+ }
+ JSONArray jsonArray = (JSONArray) rawObject;
+ lore = jsonArray;
+ break;
+ case "displayName":
+ displayName = (String) entry.getValue();
+ default:
+ }
+ }
+ return this;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public byte getData()
+ {
+ return data;
+ }
+
+ public int getAmount()
+ {
+ return amount;
+ }
+
+ public Map<Enchantment, Integer> getEnchantments()
+ {
+ return enchantments;
+ }
+
+ public List<String> getLore()
+ {
+ return lore;
+ }
+
+ public String getDisplayName()
+ {
+ return displayName;
+ }
+
+ public boolean isUnbreakable()
+ {
+ return unbreakable;
+ }
+
+ public ItemProperties setId(int id)
+ {
+ this.id = id;
+ return this;
+ }
+
+ public ItemProperties setData(byte data)
+ {
+ this.data = data;
+ return this;
+ }
+
+ public ItemProperties setAmount(int amount)
+ {
+ this.amount = amount;
+ return this;
+ }
+
+ public ItemProperties setEnchantments(Map<Enchantment, Integer> enchantments)
+ {
+ this.enchantments = enchantments;
+ return this;
+ }
+
+ public ItemProperties setLore(List<String> lore)
+ {
+ this.lore = lore;
+ return this;
+ }
+
+ public ItemProperties setDisplayName(String displayName)
+ {
+ this.displayName = displayName;
+ return this;
+ }
+
+ public ItemProperties setUnbreakable(boolean unbreakable)
+ {
+ this.unbreakable = unbreakable;
+ return this;
+ }
+}
diff --git a/src/main/java/com/redstoner/utils/ThrowingSupplier.java b/src/main/java/com/redstoner/utils/ThrowingSupplier.java
new file mode 100644
index 0000000..986746b
--- /dev/null
+++ b/src/main/java/com/redstoner/utils/ThrowingSupplier.java
@@ -0,0 +1,12 @@
+package com.redstoner.utils;
+
+/**
+ * A supplier with a throws declaration.
+ * Once again, I have more solid alternatives, but if you want it in your utils... be my guest :D
+ *
+ * @param <T> The type of object computed by this supplier.
+ */
+@FunctionalInterface
+public interface ThrowingSupplier<T> {
+ T get() throws Throwable;
+}