diff --git a/.gitignore b/.gitignore
index 71dd23b..a55f705 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,7 @@
.idea/
*.iml
*.bat
-*.xml
+dependency-reduced-pom.xml
target/
src/test/
src/main/resources/
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..72c3157
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,118 @@
+
+
+ 4.0.0
+
+ org.example
+ ProxyDiscordLink
+ 1.0-SNAPSHOT
+
+
+ 16
+ 16
+
+
+
+
+ maven-snapshots
+ https://repository.apache.org/content/repositories/snapshots/
+
+
+
+
+ clean package
+ ${project.name}
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.7.0
+
+ 16
+ 16
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.3.0-SNAPSHOT
+
+
+ package
+
+ shade
+
+
+
+
+ net.kyori.adventure.text.minimessage
+ com.alttd.proxyutils.libs.net.kyori.adventure.text.minimessage
+
+
+ net.dv8tion
+ com.alttd.proxyutils.libs.net.dv8tion
+
+
+
+
+
+
+
+
+
+ src/main
+ true
+
+
+
+
+
+
+ velocity
+ https://repo.velocitypowered.com/snapshots/
+
+
+
+
+
+ com.velocitypowered
+ velocity-api
+ 1.1.5
+ provided
+
+
+ net.luckperms
+ api
+ 5.3
+ provided
+
+
+ com.google.inject
+ guice
+ 4.1.0
+ provided
+
+
+ mysql
+ mysql-connector-java
+ 8.0.26
+
+
+ net.kyori
+ adventure-text-minimessage
+ 4.1.0-SNAPSHOT
+
+
+ net.dv8tion
+ JDA
+ 4.2.0_168
+
+
+ org.slf4j
+ slf4j-api
+ 1.7.30
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/alttd/proxydiscordlink/DiscordLink.java b/src/main/java/com/alttd/proxydiscordlink/DiscordLink.java
index 8308500..8facd81 100644
--- a/src/main/java/com/alttd/proxydiscordlink/DiscordLink.java
+++ b/src/main/java/com/alttd/proxydiscordlink/DiscordLink.java
@@ -1,6 +1,7 @@
package com.alttd.proxydiscordlink;
-import com.alttd.proxydiscordlink.commands.DiscordCommand;
+import com.alttd.proxydiscordlink.bot.Bot;
+import com.alttd.proxydiscordlink.commands.MinecraftCommand;
import com.alttd.proxydiscordlink.config.Config;
import com.alttd.proxydiscordlink.database.Database;
import com.alttd.proxydiscordlink.database.DatabaseConnection;
@@ -8,6 +9,7 @@ import com.alttd.proxydiscordlink.listeners.PlayerJoin;
import com.alttd.proxydiscordlink.listeners.PlayerLeave;
import com.alttd.proxydiscordlink.util.ALogger;
import com.alttd.proxydiscordlink.util.Cache;
+import com.alttd.proxydiscordlink.util.JarLoader;
import com.google.inject.Inject;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
@@ -32,6 +34,7 @@ public class DiscordLink {
private final Path dataDirectory;
private final Database database;
private final Cache cache;
+ private Bot bot;
@Inject
public DiscordLink(ProxyServer proxyServer, Logger proxyLogger, @DataDirectory Path proxydataDirectory)
@@ -58,6 +61,7 @@ public class DiscordLink {
}
loadCommands();
loadEvents();
+ loadBot();
}
public void reloadConfig() {
@@ -66,7 +70,7 @@ public class DiscordLink {
}
public void loadCommands() {// all (proxy)commands go here
- server.getCommandManager().register("discord", new DiscordCommand(), "discordlink");
+ server.getCommandManager().register("discord", new MinecraftCommand(), "discordlink");
}
public void loadEvents() {
@@ -74,6 +78,21 @@ public class DiscordLink {
server.getEventManager().register(this, new PlayerLeave());
}
+ public void loadBot() {
+// String JDAVersion = "4.2.0";
+// String JDABuild = "168";
+// String JDAUrl = "https://github.com/DV8FromTheWorld/JDA/releases/download/v" + JDAVersion + "/JDA-" + JDAVersion + "_" + JDABuild + "-withDependencies.jar";
+// String JDAFile = "jda-" + JDAVersion + "_" + JDABuild + ".jar";
+// if (new JarLoader().loadJar(JDAUrl, new File(new File(getDataDirectory(), "libs"), JDAFile))) {
+// ALogger.info("JDA successfully loaded");
+// } else {
+// ALogger.error("JDA could not be loaded!");
+// }
+ bot = new Bot();
+ bot.connect();
+ }
+
+
public File getDataDirectory() {
return dataDirectory.toFile();
}
@@ -97,4 +116,8 @@ public class DiscordLink {
public Cache getCache() {
return cache;
}
+
+ public Bot getBot() {
+ return bot;
+ }
}
diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/Bot.java b/src/main/java/com/alttd/proxydiscordlink/bot/Bot.java
new file mode 100644
index 0000000..9dd0c02
--- /dev/null
+++ b/src/main/java/com/alttd/proxydiscordlink/bot/Bot.java
@@ -0,0 +1,85 @@
+package com.alttd.proxydiscordlink.bot;
+
+import com.alttd.proxydiscordlink.config.BotConfig;
+import com.alttd.proxydiscordlink.util.ALogger;
+import net.dv8tion.jda.api.EmbedBuilder;
+import net.dv8tion.jda.api.JDA;
+import net.dv8tion.jda.api.JDABuilder;
+import net.dv8tion.jda.api.entities.TextChannel;
+
+import javax.security.auth.login.LoginException;
+import java.util.concurrent.TimeUnit;
+
+public class Bot {
+ private JDA jda = null;
+
+ public void connect() {
+ disconnect();
+ try {
+ jda = JDABuilder.createDefault(BotConfig.BOT_TOKEN).build();
+ jda.setAutoReconnect(true);
+ jda.addEventListener(new JDAListener());
+ DiscordCommand.loadCommands();
+ } catch (LoginException e) {
+ jda = null;
+ }
+ }
+
+ public void disconnect() {
+ if (jda != null) {
+ JDA tmp = jda;
+ jda = null;
+ new Thread(() -> {
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ignore) {
+ }
+ tmp.shutdownNow();
+ }).start();
+ }
+ }
+
+ public void sendMessageToDiscord(String channelid, String message) {
+ //sendMessageToDiscord(client.getTextChannelById(channel), message, blocking);
+ TextChannel channel = jda.getTextChannelById(channelid);
+ if (jda == null) return;
+
+ if (channel == null) return;
+
+ if (message == null) return;
+
+ // is this even used/needed?
+ //message = ChatColor.stripColor(ChatColor.translateAlternateColorCodes('&', message));
+
+ if (message.isEmpty()) return;
+
+ try {
+ channel.sendMessage(message).queue();
+ } catch (Exception e) {
+ ALogger.error("caught some exception, " + e);
+ }
+ }
+
+ public void sendEmbedToDiscord(String channelid, EmbedBuilder embedBuilder, long secondsTillDelete) {
+ //sendMessageToDiscord(client.getTextChannelById(channel), message, blocking);
+ TextChannel channel = jda.getTextChannelById(channelid);
+ if (jda == null) return;
+
+ if (channel == null) return;
+
+ if (embedBuilder == null) return;
+
+ if (!embedBuilder.isValidLength()) return;
+
+ if (embedBuilder.isEmpty()) return;
+ try {
+ if (secondsTillDelete < 0){
+ channel.sendMessage(embedBuilder.build()).queue();
+ } else {
+ channel.sendMessage(embedBuilder.build()).queue(message -> message.delete().queueAfter(secondsTillDelete, TimeUnit.SECONDS));
+ }
+ } catch (Exception e) {
+ ALogger.error("caught some exception, " + e);
+ }
+ }
+}
diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/DiscordCommand.java b/src/main/java/com/alttd/proxydiscordlink/bot/DiscordCommand.java
new file mode 100644
index 0000000..5353d34
--- /dev/null
+++ b/src/main/java/com/alttd/proxydiscordlink/bot/DiscordCommand.java
@@ -0,0 +1,37 @@
+package com.alttd.proxydiscordlink.bot;
+
+import com.alttd.proxydiscordlink.bot.commands.DiscordServerList;
+import com.alttd.proxydiscordlink.bot.commands.DiscordStaffList;
+import net.dv8tion.jda.api.entities.Message;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public abstract class DiscordCommand {
+
+ private static List commands;
+
+ public abstract String getCommand();
+ public abstract String getPermission();// TODO discord and LP permissions
+ public abstract String getDescription();
+ public abstract String getSyntax();
+
+ public abstract void handleCommand(Message message, String sender, String command, String[] args);
+
+ protected static void loadCommands() {
+ commands = new ArrayList<>();
+
+ loadCommand(new DiscordStaffList(),
+ new DiscordServerList()
+ );
+ }
+
+ private static void loadCommand(DiscordCommand ... discordCommands) {
+ Collections.addAll(commands, discordCommands);
+ }
+
+ protected static List getCommands() {
+ return commands;
+ }
+}
diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/JDAListener.java b/src/main/java/com/alttd/proxydiscordlink/bot/JDAListener.java
new file mode 100644
index 0000000..f08c896
--- /dev/null
+++ b/src/main/java/com/alttd/proxydiscordlink/bot/JDAListener.java
@@ -0,0 +1,47 @@
+package com.alttd.proxydiscordlink.bot;
+
+import com.alttd.proxydiscordlink.DiscordLink;
+import com.alttd.proxydiscordlink.config.BotConfig;
+import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent;
+import net.dv8tion.jda.api.hooks.ListenerAdapter;
+
+import java.util.Arrays;
+
+public class JDAListener extends ListenerAdapter {
+
+ private DiscordLink plugin;
+ private final Bot bot;
+
+ public JDAListener() {
+ plugin = DiscordLink.getPlugin();
+ bot = plugin.getBot();
+ }
+
+ @Override
+ public void onGuildMessageReceived(GuildMessageReceivedEvent event) {
+ if (event.getAuthor() == event.getJDA().getSelfUser()) {
+ return;
+ }
+ if (event.isWebhookMessage()) {
+ return;
+ }
+ if (event.getMessage().getChannel().getId().equals(BotConfig.COMMAND_CHANNEL)) {
+ String content = event.getMessage().getContentRaw();
+ if (content.startsWith("!") && content.length() > 1) {
+ String[] split = content.split(" ");
+ String cmd = split[0].substring(1).toLowerCase();
+ String[] args = Arrays.copyOfRange(split, 1, split.length);
+ for(DiscordCommand command : DiscordCommand.getCommands()) {
+ if(!command.getCommand().equalsIgnoreCase(cmd)) {
+ continue;
+ }
+ if(command.getPermission() != null) {
+ // TODO permission check? do we need this?
+ }
+ command.handleCommand(event.getMessage(), event.getAuthor().getName(), cmd, args);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/api/DiscordSendMessage.java b/src/main/java/com/alttd/proxydiscordlink/bot/api/DiscordSendMessage.java
new file mode 100644
index 0000000..9125b13
--- /dev/null
+++ b/src/main/java/com/alttd/proxydiscordlink/bot/api/DiscordSendMessage.java
@@ -0,0 +1,28 @@
+package com.alttd.proxydiscordlink.bot.api;
+
+import com.alttd.proxydiscordlink.DiscordLink;
+import com.alttd.proxydiscordlink.bot.Bot;
+import net.dv8tion.jda.api.EmbedBuilder;
+
+import java.awt.*;
+
+public class DiscordSendMessage {
+ public static void sendMessage(String channelId, String message)
+ {
+ Bot bot = DiscordLink.getPlugin().getBot();
+
+ bot.sendMessageToDiscord(channelId, message);
+ }
+
+ public static void sendEmbed(String channelId, String title, String description)
+ {
+ Bot bot = DiscordLink.getPlugin().getBot();
+ EmbedBuilder embedBuilder = new EmbedBuilder();
+
+ embedBuilder.setColor(Color.CYAN);
+ embedBuilder.setTitle(title);
+ embedBuilder.setDescription(description);
+
+ bot.sendEmbedToDiscord(channelId, embedBuilder, -1);
+ }
+}
diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/commands/DiscordBroadCast.java b/src/main/java/com/alttd/proxydiscordlink/bot/commands/DiscordBroadCast.java
new file mode 100644
index 0000000..0239099
--- /dev/null
+++ b/src/main/java/com/alttd/proxydiscordlink/bot/commands/DiscordBroadCast.java
@@ -0,0 +1,47 @@
+package com.alttd.proxydiscordlink.bot.commands;
+
+import com.alttd.proxydiscordlink.DiscordLink;
+import com.alttd.proxydiscordlink.bot.Bot;
+import com.alttd.proxydiscordlink.bot.DiscordCommand;
+import com.alttd.proxydiscordlink.config.BotConfig;
+import com.alttd.proxydiscordlink.util.Utilities;
+import net.dv8tion.jda.api.entities.Message;
+
+public class DiscordBroadCast extends DiscordCommand {
+
+ private DiscordLink plugin;
+ private final Bot bot;
+
+ public DiscordBroadCast() {
+ plugin = DiscordLink.getPlugin();
+ bot = plugin.getBot();
+ }
+
+ @Override
+ public String getCommand() {
+ return "broadcast";
+ }
+
+ @Override
+ public String getPermission() {
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Broadcast a message to all online players";
+ }
+
+ @Override
+ public String getSyntax() {
+ return "!broadcast";
+ }
+
+ @Override
+ public void handleCommand(Message message, String sender, String command, String[] args) {
+ //TODO also send this to the bot channel, optional command args for color and decoration?
+ String msg = String.join(" ", args);
+ bot.sendMessageToDiscord(BotConfig.COMMAND_CHANNEL, msg);
+ Utilities.broadcast(msg);
+ }
+}
diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/commands/DiscordServerList.java b/src/main/java/com/alttd/proxydiscordlink/bot/commands/DiscordServerList.java
new file mode 100644
index 0000000..bc37251
--- /dev/null
+++ b/src/main/java/com/alttd/proxydiscordlink/bot/commands/DiscordServerList.java
@@ -0,0 +1,133 @@
+package com.alttd.proxydiscordlink.bot.commands;
+
+import com.alttd.proxydiscordlink.DiscordLink;
+import com.alttd.proxydiscordlink.bot.Bot;
+import com.alttd.proxydiscordlink.bot.DiscordCommand;
+import com.alttd.proxydiscordlink.config.BotConfig;
+import com.alttd.proxydiscordlink.util.Utilities;
+import com.velocitypowered.api.proxy.Player;
+import com.velocitypowered.api.proxy.server.RegisteredServer;
+import com.velocitypowered.api.proxy.server.ServerInfo;
+import net.dv8tion.jda.api.EmbedBuilder;
+import net.dv8tion.jda.api.entities.Message;
+import net.luckperms.api.LuckPerms;
+import net.luckperms.api.model.user.User;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+public class DiscordServerList extends DiscordCommand {
+
+ private DiscordLink plugin;
+ private final Bot bot;
+
+ public DiscordServerList() {
+ plugin = DiscordLink.getPlugin();
+ bot = plugin.getBot();
+ }
+
+ @Override
+ public String getCommand() {
+ return "serverlist";
+ }
+
+ @Override
+ public String getPermission() {
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Lists all online players on the server or a specific server";
+ }
+
+ @Override
+ public String getSyntax() {
+ return "!serverlist";
+ }
+
+ @Override
+ public void handleCommand(Message message, String sender, String command, String[] args) {
+ String serverName = "Altitude";
+ Collection onlinePlayer = plugin.getProxy().getAllPlayers();
+ ServerInfo server;
+ if (args.length != 0) {
+ Optional registeredServer = plugin.getProxy().getServer(args[0]);
+ if (registeredServer.isEmpty()) {
+ return;
+ }
+ onlinePlayer = registeredServer.get().getPlayersConnected();
+ serverName = registeredServer.get().getServerInfo().getName();
+ }
+ LuckPerms luckPerms = Utilities.getLuckPerms();
+ List players = onlinePlayer
+ .stream()
+ .map(player -> luckPerms.getUserManager().getUser(player.getUniqueId()))
+ .sorted((o1, o2) -> {
+ int i = Integer.compare(luckPerms.getGroupManager().getGroup(o2.getPrimaryGroup()).getWeight().orElse(0), luckPerms.getGroupManager().getGroup(o1.getPrimaryGroup()).getWeight().orElse(0));
+ return i != 0 ? i : o1.getUsername().compareToIgnoreCase(o2.getUsername());
+ })
+ .collect(Collectors.toList());
+ EmbedBuilder embedBuilder = new EmbedBuilder();
+ String title = "Players online on " + serverName + ": " + players.size();
+ embedBuilder.setTitle(title);
+ String separator = "\n";
+ String rankname = "";
+ StringBuilder currentFieldText = new StringBuilder();
+ int entryCounter = 0;
+ int totalCharacters = title.length();
+ int fieldCounter = 0;
+
+ Iterator iterator = players.iterator();
+ while (iterator.hasNext()) {
+ User user = iterator.next();
+ if(user != null) {
+ if(!rankname.equalsIgnoreCase(user.getPrimaryGroup())) {
+ if (currentFieldText.length() != 0) {
+ totalCharacters += rankname.length() + currentFieldText.length();
+ fieldCounter++;
+ if (totalCharacters > 6000 || fieldCounter > 25) {
+ bot.sendEmbedToDiscord(BotConfig.COMMAND_CHANNEL, embedBuilder, 300);
+ embedBuilder.clearFields();
+ totalCharacters = title.length() + rankname.length() + currentFieldText.length();
+ fieldCounter = 1;
+ }
+ embedBuilder.addField(rankname, currentFieldText.toString(), true);
+ entryCounter = 0;
+ currentFieldText = new StringBuilder();
+ }
+ rankname = Utilities.capitalize(user.getPrimaryGroup());
+ } else if(rankname.equalsIgnoreCase(user.getPrimaryGroup())) {
+ currentFieldText.append(separator);
+ }
+ if (entryCounter <= 50) {
+ Optional optionalPlayer = plugin.getProxy().getPlayer(user.getUniqueId());
+ if(optionalPlayer.isPresent()) {
+ Player player = optionalPlayer.get();
+ currentFieldText.append("`").append(player.getUsername()).append("`");
+ }
+ } else if (entryCounter == 51){
+ currentFieldText.append("...");
+ }
+ entryCounter++;
+ }
+ }
+
+ if (currentFieldText.length() > 0) {
+ totalCharacters = title.length() + rankname.length() + currentFieldText.length();
+ fieldCounter++;
+ if (totalCharacters > 6000 || fieldCounter > 25) {
+ bot.sendEmbedToDiscord(BotConfig.COMMAND_CHANNEL, embedBuilder, 300);
+ embedBuilder.clearFields();
+ }
+ embedBuilder.addField(rankname, currentFieldText.toString(), true);
+ }
+
+ message.delete().queueAfter(300, TimeUnit.SECONDS);
+ bot.sendEmbedToDiscord(BotConfig.COMMAND_CHANNEL, embedBuilder, 300);
+ }
+}
diff --git a/src/main/java/com/alttd/proxydiscordlink/bot/commands/DiscordStaffList.java b/src/main/java/com/alttd/proxydiscordlink/bot/commands/DiscordStaffList.java
new file mode 100644
index 0000000..8b8c227
--- /dev/null
+++ b/src/main/java/com/alttd/proxydiscordlink/bot/commands/DiscordStaffList.java
@@ -0,0 +1,147 @@
+package com.alttd.proxydiscordlink.bot.commands;
+
+import com.alttd.proxydiscordlink.DiscordLink;
+import com.alttd.proxydiscordlink.bot.Bot;
+import com.alttd.proxydiscordlink.bot.DiscordCommand;
+import com.alttd.proxydiscordlink.config.BotConfig;
+import com.alttd.proxydiscordlink.util.Utilities;
+import com.velocitypowered.api.proxy.Player;
+import net.dv8tion.jda.api.EmbedBuilder;
+import net.dv8tion.jda.api.entities.Message;
+import net.luckperms.api.LuckPerms;
+import net.luckperms.api.model.user.User;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class DiscordStaffList extends DiscordCommand {
+
+ private DiscordLink plugin;
+ private final Bot bot;
+
+ public DiscordStaffList() {
+ plugin = DiscordLink.getPlugin();
+ bot = plugin.getBot();
+ }
+
+ @Override
+ public String getCommand() {
+ return "stafflist";
+ }
+
+ @Override
+ public String getPermission() {
+ return null;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Lists all online staff on the server";
+ }
+
+ @Override
+ public String getSyntax() {
+ return "!StaffList";
+ }
+
+ @Override
+ public void handleCommand(Message message, String sender, String command, String[] args) {
+ LuckPerms luckPerms = Utilities.getLuckPerms();
+ List staff = plugin.getProxy().getAllPlayers()
+ .stream().filter(player-> player.hasPermission("group." + BotConfig.SL_MINIMUMRANK))
+ .map(player -> luckPerms.getUserManager().getUser(player.getUniqueId()))
+ .sorted((o1, o2) -> {
+ int i = Integer.compare(luckPerms.getGroupManager().getGroup(o2.getPrimaryGroup()).getWeight().orElse(0), luckPerms.getGroupManager().getGroup(o1.getPrimaryGroup()).getWeight().orElse(0));
+ return i != 0 ? i : o1.getUsername().compareToIgnoreCase(o2.getUsername());
+ })
+ .collect(Collectors.toList());
+ EmbedBuilder embedBuilder = new EmbedBuilder();
+ String title = "Online Staff: " + staff.size() + " - Online Players: " + plugin.getProxy().getAllPlayers().size();
+ embedBuilder.setTitle(title);
+ String separator = "\n";
+ String rankname = "";
+
+ Map onlineStaff = new HashMap<>();
+ StringBuilder currentFieldText = new StringBuilder();
+ int entryCounter = 0;
+ int totalCharacters = title.length();
+ int fieldCounter = 0;
+
+ Iterator iterator = staff.iterator();
+ while (iterator.hasNext()) {
+ User user = iterator.next();
+ if(user != null) {
+ if(!rankname.equalsIgnoreCase(user.getPrimaryGroup())) {
+ if (currentFieldText.length() != 0) {
+ totalCharacters += rankname.length() + currentFieldText.length();
+ fieldCounter++;
+ if (totalCharacters > 6000 || fieldCounter > 25) {
+ bot.sendEmbedToDiscord(BotConfig.COMMAND_CHANNEL, embedBuilder, -1);
+ embedBuilder.clearFields();
+ totalCharacters = title.length() + rankname.length() + currentFieldText.length();
+ fieldCounter = 1;
+ }
+ embedBuilder.addField(rankname, currentFieldText.toString(), true);
+ entryCounter = 0;
+ currentFieldText = new StringBuilder();
+ }
+ rankname = Utilities.capitalize(user.getPrimaryGroup());
+ } else if(rankname.equalsIgnoreCase(user.getPrimaryGroup())) {
+ currentFieldText.append(separator);
+ }
+
+ Optional optionalPlayer = plugin.getProxy().getPlayer(user.getUniqueId());
+ if(optionalPlayer.isPresent()) {
+ Player player = optionalPlayer.get();
+ String currentServerName = player.getCurrentServer().isPresent() ? player.getCurrentServer().get().getServerInfo().getName() : "";
+ if (onlineStaff.containsKey(currentServerName)){
+ onlineStaff.put(currentServerName, onlineStaff.get(currentServerName) + 1);
+ } else {
+ onlineStaff.put(currentServerName, 1);
+ }
+
+ if (entryCounter <= 50) {
+ currentFieldText.append("`").append(player.getUsername()).append("`");
+ } else if (entryCounter == 51){
+ currentFieldText.append("...");
+ }
+ entryCounter++;
+ }
+ }
+ }
+
+ if (currentFieldText.length() > 0) {
+ totalCharacters = title.length() + rankname.length() + currentFieldText.length();
+ fieldCounter++;
+ if (totalCharacters > 6000 || fieldCounter > 25) {
+ bot.sendEmbedToDiscord(BotConfig.COMMAND_CHANNEL, embedBuilder, -1);
+ embedBuilder.clearFields();
+ }
+ embedBuilder.addField(rankname, currentFieldText.toString(), true);
+ currentFieldText = new StringBuilder();
+ }
+
+ for (Map.Entry entry : onlineStaff.entrySet()){
+ String serverName = entry.getKey();
+ Integer amountOfStaff = entry.getValue();
+ // this might error:/
+ int playerCount = plugin.getProxy().getServer(serverName).isPresent() ? plugin.getProxy().getServer(serverName).get().getPlayersConnected().size() - amountOfStaff : 1;
+ currentFieldText.append(serverName).append(" online staff per player ")
+ .append(amountOfStaff).append(" / ").append(Math.max(playerCount, 0)).append(" = ")
+ .append(playerCount > 0 ? Math.round(((double)amountOfStaff / playerCount) * 100.0) / 100.0 : "-").append("\n");
+ }
+
+ if (currentFieldText.length() > 0) {
+ rankname = "Staff per server";
+ totalCharacters = title.length() + rankname.length() + currentFieldText.length();
+ fieldCounter++;
+ if (totalCharacters > 6000 || fieldCounter > 25) {
+ bot.sendEmbedToDiscord(BotConfig.COMMAND_CHANNEL, embedBuilder, -1);
+ embedBuilder.clearFields();
+ }
+ embedBuilder.addField(rankname, currentFieldText.toString(), true);
+ }
+
+ bot.sendEmbedToDiscord(BotConfig.COMMAND_CHANNEL, embedBuilder, -1);
+ }
+}
diff --git a/src/main/java/com/alttd/proxydiscordlink/commands/DiscordCommand.java b/src/main/java/com/alttd/proxydiscordlink/commands/MinecraftCommand.java
similarity index 97%
rename from src/main/java/com/alttd/proxydiscordlink/commands/DiscordCommand.java
rename to src/main/java/com/alttd/proxydiscordlink/commands/MinecraftCommand.java
index d86425f..ac11707 100644
--- a/src/main/java/com/alttd/proxydiscordlink/commands/DiscordCommand.java
+++ b/src/main/java/com/alttd/proxydiscordlink/commands/MinecraftCommand.java
@@ -17,12 +17,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-public class DiscordCommand implements SimpleCommand {
+public class MinecraftCommand implements SimpleCommand {
private final List subCommands;
private final MiniMessage miniMessage;
- public DiscordCommand() {
+ public MinecraftCommand() {
subCommands = Arrays.asList(new CheckLinked(), new Link(), new Unlink(), new Reload());
miniMessage = MiniMessage.get();
}
diff --git a/src/main/java/com/alttd/proxydiscordlink/config/BotConfig.java b/src/main/java/com/alttd/proxydiscordlink/config/BotConfig.java
new file mode 100644
index 0000000..d50c7c4
--- /dev/null
+++ b/src/main/java/com/alttd/proxydiscordlink/config/BotConfig.java
@@ -0,0 +1,181 @@
+package com.alttd.proxydiscordlink.config;
+
+import com.google.common.base.Throwables;
+import com.google.common.reflect.TypeToken;
+import ninja.leaping.configurate.ConfigurationNode;
+import ninja.leaping.configurate.ConfigurationOptions;
+import ninja.leaping.configurate.objectmapping.ObjectMappingException;
+import ninja.leaping.configurate.yaml.YAMLConfigurationLoader;
+import org.yaml.snakeyaml.DumperOptions;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class BotConfig {
+ private static final Pattern PATH_PATTERN = Pattern.compile("\\.");
+ private static final String HEADER = "";
+
+ private static File CONFIG_FILE;
+ public static ConfigurationNode config;
+ public static YAMLConfigurationLoader configLoader;
+
+ static int version;
+ static boolean verbose;
+
+ public static File CONFIGPATH;
+
+ public static void init() { // todo setup share for the config
+ CONFIGPATH = new File(System.getProperty("user.home") + File.separator + "share" + File.separator + "configs" + File.separator + "DiscordLink");
+ CONFIG_FILE = new File(CONFIGPATH, "bot-config.yml");
+
+ configLoader = YAMLConfigurationLoader.builder()
+ .setFile(CONFIG_FILE)
+ .setFlowStyle(DumperOptions.FlowStyle.BLOCK)
+ .build();
+ if (!CONFIG_FILE.getParentFile().exists()) {
+ if (!CONFIG_FILE.getParentFile().mkdirs()) {
+ return;
+ }
+ }
+ if (!CONFIG_FILE.exists()) {
+ try {
+ if (!CONFIG_FILE.createNewFile()) {
+ return;
+ }
+ } catch (IOException error) {
+ error.printStackTrace();
+ }
+ }
+
+ try {
+ config = configLoader.load(ConfigurationOptions.defaults().setHeader(HEADER));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ verbose = getBoolean("verbose", true);
+ version = getInt("config-version", 1);
+
+ readConfig(Config.class, null);
+ try {
+ configLoader.save(config);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public static void readConfig(Class> clazz, Object instance) {
+ for (Method method : clazz.getDeclaredMethods()) {
+ if (Modifier.isPrivate(method.getModifiers())) {
+ if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) {
+ try {
+ method.setAccessible(true);
+ method.invoke(instance);
+ } catch (InvocationTargetException | IllegalAccessException ex) {
+ throw Throwables.propagate(ex.getCause());
+ }
+ }
+ }
+ }
+ try {
+ configLoader.save(config);
+ } catch (IOException ex) {
+ throw Throwables.propagate(ex.getCause());
+ }
+ }
+
+ public static void saveConfig() {
+ try {
+ configLoader.save(config);
+ } catch (IOException ex) {
+ throw Throwables.propagate(ex.getCause());
+ }
+ }
+
+ private static Object[] splitPath(String key) {
+ return PATH_PATTERN.split(key);
+ }
+
+ private static void set(String path, Object def) {
+ if (config.getNode(splitPath(path)).isVirtual())
+ config.getNode(splitPath(path)).setValue(def);
+ }
+
+ private static void setString(String path, String def) {
+ try {
+ if (config.getNode(splitPath(path)).isVirtual())
+ config.getNode(splitPath(path)).setValue(TypeToken.of(String.class), def);
+ } catch (ObjectMappingException ex) {
+ }
+ }
+
+ private static boolean getBoolean(String path, boolean def) {
+ set(path, def);
+ return config.getNode(splitPath(path)).getBoolean(def);
+ }
+
+ private static double getDouble(String path, double def) {
+ set(path, def);
+ return config.getNode(splitPath(path)).getDouble(def);
+ }
+
+ private static int getInt(String path, int def) {
+ set(path, def);
+ return config.getNode(splitPath(path)).getInt(def);
+ }
+
+ private static String getString(String path, String def) {
+ setString(path, def);
+ return config.getNode(splitPath(path)).getString(def);
+ }
+
+ private static Long getLong(String path, Long def) {
+ set(path, def);
+ return config.getNode(splitPath(path)).getLong(def);
+ }
+
+ private static List getList(String path, T def) {
+ try {
+ set(path, def);
+ return config.getNode(splitPath(path)).getList(TypeToken.of(String.class));
+ } catch (ObjectMappingException ex) {
+ }
+ return new ArrayList<>();
+ }
+
+ private static ConfigurationNode getNode(String path) {
+ if (config.getNode(splitPath(path)).isVirtual()) {
+ //new RegexConfig("Dummy");
+ }
+ config.getChildrenMap();
+ return config.getNode(splitPath(path));
+ }
+
+
+ /**
+ * ONLY EDIT ANYTHING BELOW THIS LINE
+ **/
+
+ public static String BOT_TOKEN = "";
+ public static String COMMAND_CHANNEL = "";
+ private static void settings()
+ {
+ BOT_TOKEN = getString("settings.token", BOT_TOKEN);
+ COMMAND_CHANNEL = getString("settings.command_channel", COMMAND_CHANNEL);
+ }
+
+ public static String SL_MINIMUMRANK = "trainee";
+ public static String SL_HOVERMESSAGE = "Click here to message %player% on %servername%.";
+ public static String SL_CLICKCOMMAND = "/msg %player%";
+ private static void Stafflist() {
+ SL_MINIMUMRANK = getString("commands.staff-list.minimum-rank", SL_MINIMUMRANK);
+ SL_HOVERMESSAGE = getString("commands.staff-list.hover-message", SL_HOVERMESSAGE);
+ SL_CLICKCOMMAND = getString("commands.staff-list.click-command", SL_CLICKCOMMAND);
+ }
+}
diff --git a/src/main/java/com/alttd/proxydiscordlink/util/JarLoader.java b/src/main/java/com/alttd/proxydiscordlink/util/JarLoader.java
new file mode 100644
index 0000000..c2724b8
--- /dev/null
+++ b/src/main/java/com/alttd/proxydiscordlink/util/JarLoader.java
@@ -0,0 +1,131 @@
+package com.alttd.proxydiscordlink.util;
+
+import com.alttd.proxydiscordlink.DiscordLink;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+
+public class JarLoader {
+
+ private static final Method ADD_URL_METHOD;
+
+ static {
+ try {
+ ADD_URL_METHOD = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
+ ADD_URL_METHOD.setAccessible(true);
+ } catch (NoSuchMethodException e) {
+ throw new ExceptionInInitializerError(e);
+ }
+ }
+
+ private URLClassLoader classLoader;
+
+ public JarLoader() {
+ classLoader = ((URLClassLoader) DiscordLink.getPlugin().getClass().getClassLoader());
+ }
+
+ public boolean loadJar(String url, File file) {
+ try {
+ if (!file.getParentFile().exists()) {
+ if (!file.getParentFile().mkdirs()) {
+ ALogger.warn("Could not create directory: " + file.getParentFile().getAbsolutePath());
+ }
+ }
+
+ if (file.exists() && file.isDirectory()) {
+ Files.delete(file.toPath());
+ }
+
+ if (!file.exists()) {
+ ALogger.info("Jar not found! (" + file.getName() + ")");
+ ALogger.info("Downloading jar from " + url);
+ downloadJar(url, file);
+ }
+
+ ADD_URL_METHOD.invoke(classLoader, file.toPath().toUri().toURL());
+ return true;
+ } catch (IOException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ private void downloadJar(String url, File file) throws IOException {
+ HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
+ conn.setInstanceFollowRedirects(true);
+
+ boolean redirect;
+
+ do {
+ int status = conn.getResponseCode();
+ redirect = status == HttpURLConnection.HTTP_MOVED_TEMP ||
+ status == HttpURLConnection.HTTP_MOVED_PERM ||
+ status == HttpURLConnection.HTTP_SEE_OTHER;
+
+ if (redirect) {
+ String newUrl = conn.getHeaderField("Location");
+ String cookies = conn.getHeaderField("Set-Cookie");
+
+ conn = (HttpURLConnection) new URL(newUrl).openConnection();
+ conn.setRequestProperty("Cookie", cookies);
+ conn.addRequestProperty("Accept-Language", "en-US,en;q=0.8");
+ }
+ } while (redirect);
+
+ Progress progress = new Progress(conn.getContentLength());
+ progress.start();
+
+ try (BufferedInputStream in = new BufferedInputStream(conn.getInputStream());
+ FileOutputStream fileOutputStream = new FileOutputStream(file)) {
+ byte[] dataBuffer = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) {
+ progress.current += bytesRead;
+ fileOutputStream.write(dataBuffer, 0, bytesRead);
+ }
+ }
+
+ progress.interrupt();
+ }
+
+ private class Progress extends Thread {
+ private final long total;
+ private long current;
+
+ private Progress(long total) {
+ this.total = total;
+ }
+
+ @Override
+ public void run() {
+ try {
+ //noinspection InfiniteLoopStatement
+ while (true) {
+ logProgress();
+ sleep(1000);
+ }
+ } catch (InterruptedException ignore) {
+ }
+ }
+
+ @Override
+ public void interrupt() {
+ logProgress();
+ super.interrupt();
+ }
+
+ private void logProgress() {
+ ALogger.info(String.format("progress: %s%% (%s/%s)",
+ (int) ((((double) current) / ((double) total)) * 100D),
+ current, total));
+ }
+ }
+}
diff --git a/src/main/java/com/alttd/proxydiscordlink/util/Utilities.java b/src/main/java/com/alttd/proxydiscordlink/util/Utilities.java
index b7ea72b..052de82 100644
--- a/src/main/java/com/alttd/proxydiscordlink/util/Utilities.java
+++ b/src/main/java/com/alttd/proxydiscordlink/util/Utilities.java
@@ -1,10 +1,10 @@
package com.alttd.proxydiscordlink.util;
+import com.alttd.proxydiscordlink.DiscordLink;
import com.alttd.proxydiscordlink.config.Config;
-import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.Player;
+import com.velocitypowered.api.proxy.ProxyServer;
import net.kyori.adventure.text.minimessage.MiniMessage;
-import net.kyori.adventure.text.minimessage.Template;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
import net.luckperms.api.model.user.User;
@@ -86,4 +86,16 @@ public class Utilities {
public static String getRankName(Player player) {
return getLuckPerms().getUserManager().getUser(player.getUniqueId()).getPrimaryGroup();
}
+
+ public static String capitalize(String str) {
+ if(str == null || str.isEmpty()) {
+ return str;
+ }
+ return str.substring(0, 1).toUpperCase() + str.substring(1);
+ }
+
+ public static void broadcast(String message) {
+ ProxyServer server = DiscordLink.getPlugin().getProxy();
+ server.sendMessage(miniMessage.parse(message));
+ }
}