diff --git a/pom.xml b/pom.xml
index 804a8c4..67a8bf8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -138,28 +138,24 @@
2.11.5
provided
-
com.github.oshi
oshi-core
6.5.0
compile
-
com.influxdb
influxdb-client-java
7.0.0
compile
-
com.viaversion
viaversion-api
4.9.2
provided
-
com.vexsoftware
nuvotifier-universal
@@ -167,5 +163,17 @@
${basedir}/lib/nuvotifier.jar
system
+
+ net.dv8tion
+ JDA
+ 5.0.0-beta.21
+
+
+ club.minnced
+ opus-java
+
+
+ compile
+
\ No newline at end of file
diff --git a/src/main/java/cc/fascinated/Aetheria.java b/src/main/java/cc/fascinated/Aetheria.java
index 5c28962..a397fc1 100644
--- a/src/main/java/cc/fascinated/Aetheria.java
+++ b/src/main/java/cc/fascinated/Aetheria.java
@@ -1,6 +1,7 @@
package cc.fascinated;
import cc.fascinated.account.AccountManager;
+import cc.fascinated.bot.DiscordBot;
import cc.fascinated.chat.ChatManager;
import cc.fascinated.command.CommandManager;
import cc.fascinated.commandspy.CommandSpyManager;
@@ -27,11 +28,13 @@ public class Aetheria extends JavaPlugin {
@Getter
private static final BuildData buildData = new BuildData();
+
/**
* The instance of the plugin.
*/
public static Aetheria INSTANCE;
- public static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(2, 8, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
+ public static ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(2, 8, 0L,
+ TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
public Aetheria() {
INSTANCE = this;
@@ -45,7 +48,6 @@ public class Aetheria extends JavaPlugin {
Lang.clear();
new AccountManager();
-
new EventManager();
new CommandManager();
new WorldSizeManager();
@@ -58,5 +60,6 @@ public class Aetheria extends JavaPlugin {
new RenderDistanceManager();
new VoteManager();
new StaffChatManager();
+ new DiscordBot();
}
}
\ No newline at end of file
diff --git a/src/main/java/cc/fascinated/account/Account.java b/src/main/java/cc/fascinated/account/Account.java
index e5a1a34..6849585 100644
--- a/src/main/java/cc/fascinated/account/Account.java
+++ b/src/main/java/cc/fascinated/account/Account.java
@@ -69,7 +69,7 @@ public class Account {
*/
private long lastLogin;
- public Account(UUID uuid) {
+ public Account(UUID uuid, String name) {
//log.info("Loading account for " + uuid);
boolean newAccount = false;
@@ -100,7 +100,7 @@ public class Account {
this.lastLogin = config.getLong("lastLogin");
this.lastLogin = System.currentTimeMillis(); // Update last login
- this.name = Bukkit.getOfflinePlayer(uuid).getName();
+ this.name = name; // Update the name
// Load profiles
this.playerColorProfile = new PlayerColorProfile(this, this.getProfileSection(playerColorProfileId));
@@ -204,6 +204,16 @@ public class Account {
return getPlayer().isOp();
}
+ /**
+ * Set if the player has the permission.
+ *
+ * @param permission the permission to check
+ * @return if the player has the permission
+ */
+ public boolean hasPermission(String permission) {
+ return getPlayer().hasPermission(permission);
+ }
+
/**
* Saves the account to disk.
*
diff --git a/src/main/java/cc/fascinated/account/AccountManager.java b/src/main/java/cc/fascinated/account/AccountManager.java
index 803b8bb..e549f8e 100644
--- a/src/main/java/cc/fascinated/account/AccountManager.java
+++ b/src/main/java/cc/fascinated/account/AccountManager.java
@@ -2,16 +2,18 @@ package cc.fascinated.account;
import cc.fascinated.Aetheria;
import cc.fascinated.account.command.SaveAccountsCommand;
+import cc.fascinated.bot.DiscordBot;
+import cc.fascinated.bot.DiscordChannel;
import cc.fascinated.command.CommandManager;
import cc.fascinated.config.Config;
import cc.fascinated.config.Lang;
import cc.fascinated.playercolor.PlayerColorProfile;
-import cc.fascinated.utils.DiscordWebhook;
import cc.fascinated.utils.Manager;
import cc.fascinated.utils.Priority;
import cc.fascinated.utils.Style;
import com.viaversion.viaversion.api.Via;
import lombok.extern.log4j.Log4j2;
+import net.dv8tion.jda.api.EmbedBuilder;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -20,7 +22,8 @@ import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
-import java.io.IOException;
+import java.awt.*;
+import java.util.List;
import java.util.*;
import java.util.concurrent.TimeUnit;
@@ -38,7 +41,7 @@ public class AccountManager extends Manager implements Listener {
if (isAccountLoaded(player.getUniqueId())) { // Don't load the account if it's already loaded
continue;
}
- loadAccount(player.getUniqueId());
+ loadAccount(player.getUniqueId(), player.getName());
}
Bukkit.getAsyncScheduler().runAtFixedRate(Aetheria.INSTANCE, (task) -> {
@@ -46,6 +49,21 @@ public class AccountManager extends Manager implements Listener {
}, SAVE_INTERVAL, SAVE_INTERVAL, TimeUnit.MINUTES);
}
+ /**
+ * Gets a list of all online accounts.
+ *
+ * @return the online accounts
+ */
+ public static List getOnlineAccounts() {
+ List accounts = new ArrayList<>();
+ for (Account account : ACCOUNTS.values()) {
+ if (account.isOnline()) {
+ accounts.add(account);
+ }
+ }
+ return accounts;
+ }
+
/**
* Gets the account for the specified player.
*
@@ -60,9 +78,10 @@ public class AccountManager extends Manager implements Listener {
* Registers an account for the specified player.
*
* @param uuid the player's UUID
+ * @param name the player's name
*/
- private static void loadAccount(UUID uuid) {
- Account account = new Account(uuid);
+ private static void loadAccount(UUID uuid, String name) {
+ Account account = new Account(uuid, name);
ACCOUNTS.put(uuid, account);
}
@@ -105,10 +124,11 @@ public class AccountManager extends Manager implements Listener {
@EventHandler
public void onAsyncPlayerPreLoginEvent(AsyncPlayerPreLoginEvent event) {
UUID uuid = event.getUniqueId();
+ String name = event.getName();
if (isAccountLoaded(uuid)) { // Account already loaded
return;
}
- loadAccount(uuid); // Load the account into memory
+ loadAccount(uuid, name); // Load the account into memory
}
@Override
@@ -119,22 +139,13 @@ public class AccountManager extends Manager implements Listener {
if (!account.getPlayer().hasPlayedBefore()) {
joinMessage = Lang.FIRST_JOIN_MESSAGE.getAsString();
- // Send a notification to the discord log channel
- Aetheria.EXECUTOR.execute(() -> {
- // todo: re-code this it's so ugly
- DiscordWebhook discordWebhook = new DiscordWebhook(Config.DISCORD_LOG_WEBHOOK.getAsString());
- DiscordWebhook.EmbedObject embed = new DiscordWebhook.EmbedObject();
- embed.setTitle("New Player Joined");
- embed.addField("Name", account.getName(), true);
- embed.addField("UUID", account.getUuid().toString(), true);
-
- discordWebhook.addEmbed(embed);
- try {
- discordWebhook.execute();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- });
+ DiscordBot.sendEmbed(DiscordChannel.PLAYER_LOGS, new EmbedBuilder()
+ .setThumbnail("https://crafatar.com/avatars/" + account.getUuid())
+ .setColor(Color.GREEN)
+ .setTitle("New Player Joined")
+ .addField("Player", account.getName(), true)
+ .addField("UUID", account.getUuid().toString(), true)
+ );
}
event.joinMessage(Style.getMiniMessage().deserialize(joinMessage
.replace("%player%", account.getName())
diff --git a/src/main/java/cc/fascinated/account/command/DeleteAccountCommand.java b/src/main/java/cc/fascinated/account/command/DeleteAccountCommand.java
new file mode 100644
index 0000000..d6f9b61
--- /dev/null
+++ b/src/main/java/cc/fascinated/account/command/DeleteAccountCommand.java
@@ -0,0 +1,16 @@
+package cc.fascinated.account.command;
+
+import cc.fascinated.account.Account;
+import cc.fascinated.command.Command;
+
+public class DeleteAccountCommand extends Command {
+
+ public DeleteAccountCommand() {
+ super("deleteaccount", "aetheria.command.deleteaccount");
+ }
+
+ @Override
+ public void execute(Account account, String[] args) {
+
+ }
+}
diff --git a/src/main/java/cc/fascinated/bot/DiscordBot.java b/src/main/java/cc/fascinated/bot/DiscordBot.java
new file mode 100644
index 0000000..300ea9a
--- /dev/null
+++ b/src/main/java/cc/fascinated/bot/DiscordBot.java
@@ -0,0 +1,105 @@
+package cc.fascinated.bot;
+
+import cc.fascinated.config.Config;
+import cc.fascinated.utils.Manager;
+import lombok.Getter;
+import lombok.extern.log4j.Log4j2;
+import net.dv8tion.jda.api.EmbedBuilder;
+import net.dv8tion.jda.api.JDA;
+import net.dv8tion.jda.api.JDABuilder;
+import net.dv8tion.jda.api.OnlineStatus;
+import net.dv8tion.jda.api.entities.Activity;
+import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
+import net.dv8tion.jda.api.utils.cache.CacheFlag;
+import org.bukkit.Bukkit;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+@Getter @Log4j2
+public class DiscordBot extends Manager {
+
+ /**
+ * How often we should update the Discord presence.
+ */
+ private final int statusUpdateInterval = 1000 * 60 * 5;
+
+ /**
+ * The Discord bot instance.
+ */
+ @Getter
+ private static JDA jda;
+
+ /**
+ * The thread that the bot runs on.
+ */
+ private final Thread thread;
+
+ public DiscordBot() {
+ this.thread = new Thread(() -> {
+ log.info("Starting Discord bot...");
+ JDABuilder builder = JDABuilder.createDefault(Config.DISCORD_TOKEN.getAsString());
+ builder.disableCache(
+ CacheFlag.MEMBER_OVERRIDES,
+ CacheFlag.VOICE_STATE,
+ CacheFlag.ACTIVITY
+ );
+
+ try {
+ jda = builder.build();
+ jda.awaitReady();
+ log.info("Discord bot started successfully.");
+ } catch (Exception ex) {
+ log.error("Failed to start Discord bot.", ex);
+ return;
+ }
+
+ new Timer().scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ int playerCount = Bukkit.getOnlinePlayers().size();
+
+ jda.getPresence().setPresence(OnlineStatus.ONLINE, Activity.watching("over " + playerCount + " players"));
+ }
+ }, 0, statusUpdateInterval);
+ });
+ this.thread.setName("DiscordBot");
+ this.thread.start();
+ }
+
+ /**
+ * Sends a message to the Discord channel.
+ *
+ * @param channel the channel
+ * @param message the message
+ */
+ public static void sendMessage(DiscordChannel channel, String message) {
+ TextChannel textChannel = jda.getTextChannelById(channel.getId());
+ if (textChannel == null) {
+ log.error("Could not find the text channel with the ID " + channel.getId());
+ return;
+ }
+ textChannel.sendMessage(message).queue();
+ }
+
+ /**
+ * Sends an embed to the Discord channel.
+ *
+ * @param channel the channel
+ * @param embed the embed
+ */
+ public static void sendEmbed(DiscordChannel channel, EmbedBuilder embed) {
+ TextChannel textChannel = jda.getTextChannelById(channel.getId());
+ if (textChannel == null) {
+ log.error("Could not find the text channel with the ID " + channel.getId());
+ return;
+ }
+ textChannel.sendMessageEmbeds(embed.build()).queue();
+ }
+
+ @Override
+ public void onAetheriaDisable() {
+ log.info("Shutting down Discord bot...");
+ jda.shutdownNow();
+ }
+}
diff --git a/src/main/java/cc/fascinated/bot/DiscordChannel.java b/src/main/java/cc/fascinated/bot/DiscordChannel.java
new file mode 100644
index 0000000..ecdb8c3
--- /dev/null
+++ b/src/main/java/cc/fascinated/bot/DiscordChannel.java
@@ -0,0 +1,16 @@
+package cc.fascinated.bot;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter @RequiredArgsConstructor
+public enum DiscordChannel {
+
+ PLAYER_LOGS("1223161810157568020"),
+ VOTE_LOGS("1225868584522219570");
+
+ /**
+ * The ID of the Discord channel.
+ */
+ private final String id;
+}
diff --git a/src/main/java/cc/fascinated/command/Command.java b/src/main/java/cc/fascinated/command/Command.java
index 1739e7f..23d18e5 100644
--- a/src/main/java/cc/fascinated/command/Command.java
+++ b/src/main/java/cc/fascinated/command/Command.java
@@ -54,7 +54,7 @@ public abstract class Command implements CommandExecutor, TabCompleter {
}
@Override
- public boolean onCommand(@NotNull CommandSender commandSender, org.bukkit.command.@NotNull Command command, @NotNull String s, @NotNull String[] strings) {
+ public final boolean onCommand(@NotNull CommandSender commandSender, org.bukkit.command.@NotNull Command command, @NotNull String s, @NotNull String[] strings) {
if (this.permission != null && !commandSender.hasPermission(permission)) {
commandSender.sendMessage("§cYou do not have permission to execute this command.");
return true;
@@ -67,7 +67,7 @@ public abstract class Command implements CommandExecutor, TabCompleter {
}
@Override
- public @Nullable List onTabComplete(@NotNull CommandSender commandSender, org.bukkit.command.@NotNull Command command, @NotNull String s, @NotNull String[] strings) {
+ public final @Nullable List onTabComplete(@NotNull CommandSender commandSender, org.bukkit.command.@NotNull Command command, @NotNull String s, @NotNull String[] strings) {
if (this.permission != null && !commandSender.hasPermission(permission)) {
return null;
}
diff --git a/src/main/java/cc/fascinated/command/CommandManager.java b/src/main/java/cc/fascinated/command/CommandManager.java
index c5dc66d..689d7ad 100644
--- a/src/main/java/cc/fascinated/command/CommandManager.java
+++ b/src/main/java/cc/fascinated/command/CommandManager.java
@@ -14,6 +14,11 @@ public class CommandManager {
registerCommand(new GitCommand());
}
+ /**
+ * Registers a command.
+ *
+ * @param command The command to register.
+ */
public static void registerCommand(Command command) {
if (command == null) {
throw new IllegalArgumentException("Command cannot be null.");
diff --git a/src/main/java/cc/fascinated/config/Config.java b/src/main/java/cc/fascinated/config/Config.java
index e650f0e..9e5b9ae 100644
--- a/src/main/java/cc/fascinated/config/Config.java
+++ b/src/main/java/cc/fascinated/config/Config.java
@@ -14,7 +14,7 @@ public enum Config {
INFLUXDB_TOKEN("influxdb.token"),
INFLUXDB_ORG("influxdb.org"),
INFLUXDB_BUCKET("influxdb.bucket"),
- DISCORD_LOG_WEBHOOK("discord.log-webhook"),
+ DISCORD_TOKEN("discord.token"),
MOTD_HEADER("motd.header"),
MOTD_FORMAT("motd.format"),
MOTD_LIST("motd.motds"),
diff --git a/src/main/java/cc/fascinated/playercolor/PlayerColorManager.java b/src/main/java/cc/fascinated/playercolor/PlayerColorManager.java
index 0087327..391bc10 100644
--- a/src/main/java/cc/fascinated/playercolor/PlayerColorManager.java
+++ b/src/main/java/cc/fascinated/playercolor/PlayerColorManager.java
@@ -20,15 +20,6 @@ public class PlayerColorManager extends Manager {
*/
@Getter
private static final List validColors = List.of(
-// NamedTextColor.RED,
-// NamedTextColor.GREEN,
-// NamedTextColor.BLUE,
-// NamedTextColor.YELLOW,
-// NamedTextColor.AQUA,
-// NamedTextColor.DARK_AQUA,
-// NamedTextColor.GRAY,
-// NamedTextColor.LIGHT_PURPLE,
-// NamedTextColor.WHITE
NamedTextColor.DARK_BLUE,
NamedTextColor.DARK_GREEN,
NamedTextColor.DARK_AQUA,
diff --git a/src/main/java/cc/fascinated/staffchat/StaffChatManager.java b/src/main/java/cc/fascinated/staffchat/StaffChatManager.java
index 22b6769..6d83460 100644
--- a/src/main/java/cc/fascinated/staffchat/StaffChatManager.java
+++ b/src/main/java/cc/fascinated/staffchat/StaffChatManager.java
@@ -1,11 +1,33 @@
package cc.fascinated.staffchat;
+import cc.fascinated.account.Account;
+import cc.fascinated.account.AccountManager;
+import cc.fascinated.config.Lang;
import cc.fascinated.staffchat.command.StaffChatCommand;
import cc.fascinated.utils.Manager;
+import org.bukkit.Bukkit;
public class StaffChatManager extends Manager {
public StaffChatManager() {
registerCommand(new StaffChatCommand());
}
+
+ /**
+ * Sends a message to all staff members.
+ *
+ * @param sender the account who sent the message
+ * @param message the message to send
+ */
+ public static void sendMessage(Account sender, String message) {
+ AccountManager.getOnlineAccounts().stream()
+ .filter(account -> account.hasPermission("aetheria.command.staffchat"))
+ .forEach(account -> {
+ account.sendMessage(Lang.STAFF_CHAT_FORMAT.getAsString()
+ .replace("%player%", sender.getPlayer().getName())
+ .replace("%message%", message)
+ .replace("player-color", sender.getPlayerColorProfile().getColor().toString())
+ );
+ });
+ }
}
diff --git a/src/main/java/cc/fascinated/staffchat/command/StaffChatCommand.java b/src/main/java/cc/fascinated/staffchat/command/StaffChatCommand.java
index 397440a..5cb201c 100644
--- a/src/main/java/cc/fascinated/staffchat/command/StaffChatCommand.java
+++ b/src/main/java/cc/fascinated/staffchat/command/StaffChatCommand.java
@@ -1,10 +1,9 @@
package cc.fascinated.staffchat.command;
import cc.fascinated.account.Account;
-import cc.fascinated.account.AccountManager;
import cc.fascinated.command.Command;
import cc.fascinated.config.Lang;
-import org.bukkit.Bukkit;
+import cc.fascinated.staffchat.StaffChatManager;
public class StaffChatCommand extends Command {
@@ -18,21 +17,6 @@ public class StaffChatCommand extends Command {
account.sendMessage(Lang.STAFF_CHAT_USAGE.getAsString());
return;
}
-
- StringBuilder message = new StringBuilder();
- for (String arg : args) {
- message.append(arg).append(" ");
- }
-
- Bukkit.getOnlinePlayers().stream()
- .filter(player -> player.hasPermission("aetheria.command.staffchat"))
- .forEach(player -> {
- Account staffAccount = AccountManager.getAccount(player.getUniqueId());
- staffAccount.sendMessage(Lang.STAFF_CHAT_FORMAT.getAsString()
- .replace("%player%", account.getPlayer().getName())
- .replace("%message%", message.toString())
- .replace("player-color", account.getPlayerColorProfile().getColor().toString())
- );
- });
+ StaffChatManager.sendMessage(account, String.join(" ", args));
}
}
diff --git a/src/main/java/cc/fascinated/vote/VoteManager.java b/src/main/java/cc/fascinated/vote/VoteManager.java
index a1edd5d..20615fd 100644
--- a/src/main/java/cc/fascinated/vote/VoteManager.java
+++ b/src/main/java/cc/fascinated/vote/VoteManager.java
@@ -1,6 +1,8 @@
package cc.fascinated.vote;
import cc.fascinated.account.Account;
+import cc.fascinated.bot.DiscordBot;
+import cc.fascinated.bot.DiscordChannel;
import cc.fascinated.command.CommandManager;
import cc.fascinated.config.Lang;
import cc.fascinated.playercolor.PlayerColorProfile;
@@ -8,6 +10,9 @@ import cc.fascinated.utils.Manager;
import cc.fascinated.utils.MessageUtils;
import cc.fascinated.vote.command.VoteStatsCommand;
import com.vexsoftware.votifier.model.VotifierEvent;
+import net.dv8tion.jda.api.EmbedBuilder;
+
+import java.awt.*;
public class VoteManager extends Manager {
@@ -28,5 +33,12 @@ public class VoteManager extends Manager {
account.sendMessage(Lang.VOTE_VOTED.getAsString()
.replace("%votes%", voteProfile.getTotalVotes() + "")
);
+
+ DiscordBot.sendEmbed(DiscordChannel.VOTE_LOGS, new EmbedBuilder()
+ .setTitle("Player Voted")
+ .setColor(Color.GREEN)
+ .addField("Player", account.getPlayer().getName(), true)
+ .addField("Votes", voteProfile.getTotalVotes() + "", true)
+ );
}
}
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 4ea86ef..2b77a15 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -5,7 +5,7 @@ influxdb:
bucket: "aetheria"
discord:
- log-webhook: "https://discord.com/api/webhooks/1223162714822807572/jkqXHdcf4ov7MTC4fxx8MI2rSCoQTHONua8VOJa3ie5OtHBthqd5MGM7WGd7oHF52OOm"
+ token: "MTEyOTEyMDY0NTk3Mjc2Njc3MA.G7VXPL.8iDzdTxScweAKByKnwY6PFcK07AehFfNvf_2Hk"
version-warning:
min-version: 763 # 1.20