diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml
index 27df5ab..8f865a7 100644
--- a/dependency-reduced-pom.xml
+++ b/dependency-reduced-pom.xml
@@ -4,7 +4,7 @@
com.adzel.velocitybroadcast
velocitybroadcast
VelocityBroadcast
- 0.2-pre
+ 0.3-pre
Broadcast plugin for Minecraft Velocity proxy.
@@ -25,7 +25,7 @@
shade
- true
+ false
@@ -37,6 +37,10 @@
velocitypowered-repo
https://repo.velocitypowered.com/releases/
+
+ central
+ https://repo.maven.apache.org/maven2
+
diff --git a/pom.xml b/pom.xml
index 4bfc26d..dac361d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.adzel.velocitybroadcast
velocitybroadcast
- 0.2-pre
+ 0.3-pre
jar
VelocityBroadcast
Broadcast plugin for Minecraft Velocity proxy.
@@ -21,6 +21,10 @@
velocitypowered-repo
https://repo.velocitypowered.com/releases/
+
+ central
+ https://repo.maven.apache.org/maven2
+
@@ -45,6 +49,34 @@
adventure-text-minimessage
4.15.0
+
+
+
+ org.json
+ json
+ 20240303
+
+
+
+
+ org.xerial
+ sqlite-jdbc
+ 3.43.2.2
+
+
+
+
+ com.mysql
+ mysql-connector-j
+ 8.4.0
+
+
+
+
+ org.yaml
+ snakeyaml
+ 2.2
+
@@ -71,8 +103,7 @@
shade
- true
-
+ false
@@ -80,3 +111,5 @@
+
\ No newline at end of file
diff --git a/src/main/java/com/adzel/velocitybroadcast/BroadcastCommand.java b/src/main/java/com/adzel/velocitybroadcast/BroadcastCommand.java
index 21d1fd5..d70d6e2 100644
--- a/src/main/java/com/adzel/velocitybroadcast/BroadcastCommand.java
+++ b/src/main/java/com/adzel/velocitybroadcast/BroadcastCommand.java
@@ -2,8 +2,10 @@ package com.adzel.velocitybroadcast;
import java.util.List;
+import com.adzel.velocitybroadcast.util.DatabaseManager;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
+import com.velocitypowered.api.proxy.Player;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
@@ -11,9 +13,11 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
public class BroadcastCommand implements SimpleCommand {
private final VelocityBroadcast plugin;
+ private final DatabaseManager databaseManager;
public BroadcastCommand(VelocityBroadcast plugin) {
this.plugin = plugin;
+ this.databaseManager = plugin.getDatabaseManager();
}
@Override
@@ -42,5 +46,13 @@ public class BroadcastCommand implements SimpleCommand {
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Broadcast] Sent: " + fullMessage);
}
+
+ // ✅ Log to the database
+ String sender = (source instanceof Player)
+ ? ((Player) source).getUsername()
+ : "Console";
+
+ String sourceServer = plugin.getServer().getBoundAddress().toString(); // optional
+ databaseManager.logBroadcast(sender, messageRaw, sourceServer);
}
}
diff --git a/src/main/java/com/adzel/velocitybroadcast/ConfigHandler.java b/src/main/java/com/adzel/velocitybroadcast/ConfigHandler.java
index 634da63..bb3fd04 100644
--- a/src/main/java/com/adzel/velocitybroadcast/ConfigHandler.java
+++ b/src/main/java/com/adzel/velocitybroadcast/ConfigHandler.java
@@ -1,16 +1,16 @@
package com.adzel.velocitybroadcast;
-import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
import org.slf4j.Logger;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.representer.Representer;
public class ConfigHandler {
private final Path configPath;
@@ -20,14 +20,34 @@ public class ConfigHandler {
private boolean versionCheckEnabled = true;
private String prefix = "&9&l[&3&lServer&9&l]&r ";
+ private String dbType = "sqlite";
+ private String dbHost = "localhost";
+ private int dbPort = 3306;
+ private String dbName = "velocitybroadcast";
+ private String dbUser = "vb_user";
+ private String dbPassword = "securepassword";
+
private static final String CURRENT_VERSION = VelocityBroadcast.PLUGIN_VERSION;
private static final String VERSION_LINE = "# DO NOT EDIT\nPlugin Version: '" + CURRENT_VERSION + "' # Do not edit this value, as it will mess up version checking and break the plugin";
+ private final Yaml yaml;
+
public ConfigHandler(Path configPath, Logger logger) {
this.configPath = configPath;
this.logger = logger;
+
+ DumperOptions options = new DumperOptions();
+ options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
+ options.setIndent(2);
+ options.setPrettyFlow(true);
+
+ Representer representer = new Representer(options);
+ representer.getPropertyUtils().setSkipMissingProperties(true);
+
+ yaml = new Yaml(representer, options);
}
+ @SuppressWarnings("unchecked")
public void load() {
try {
Files.createDirectories(configPath.getParent());
@@ -39,38 +59,34 @@ public class ConfigHandler {
return;
}
- List lines = Files.readAllLines(configPath);
- String fileVersion = null;
-
- for (String line : lines) {
- if (line.trim().startsWith("Plugin Version:")) {
- fileVersion = line.replaceAll(".*'(.*?)'.*", "$1").trim();
- break;
- }
- }
+ String fileVersion = Files.readAllLines(configPath).stream()
+ .filter(line -> line.startsWith("Plugin Version:"))
+ .map(line -> line.replaceAll(".*'(.*?)'.*", "$1").trim())
+ .findFirst()
+ .orElse(null);
if (fileVersion == null || !fileVersion.equals(CURRENT_VERSION)) {
shouldSave = true;
}
- try (BufferedReader reader = Files.newBufferedReader(configPath)) {
- Map configMap = reader.lines()
- .filter(line -> line.contains(":") && !line.trim().startsWith("#"))
- .map(line -> line.replaceAll("#.*", "").split(":", 2))
- .collect(Collectors.toMap(
- a -> a[0].trim(),
- a -> a[1].trim().replaceAll("^['\"]|['\"]$", ""),
- (a, b) -> b,
- LinkedHashMap::new
- ));
+ Map root = yaml.load(Files.newBufferedReader(configPath));
+ if (root == null) root = new LinkedHashMap<>();
- debugEnabled = Boolean.parseBoolean(configMap.getOrDefault("debug-messages-enabled", "false"));
- versionCheckEnabled = Boolean.parseBoolean(configMap.getOrDefault("version-check-enabled", "true"));
- prefix = configMap.getOrDefault("prefix", "&9&l[&3&lServer&9&l]&r ");
- }
+ Map general = (Map) root.getOrDefault("general", new LinkedHashMap<>());
+ debugEnabled = Boolean.parseBoolean(String.valueOf(general.getOrDefault("debug-messages-enabled", "false")));
+ versionCheckEnabled = Boolean.parseBoolean(String.valueOf(general.getOrDefault("version-check-enabled", "true")));
+ prefix = String.valueOf(general.getOrDefault("prefix", "&9&l[&3&lServer&9&l]&r "));
+
+ Map database = (Map) root.getOrDefault("database", new LinkedHashMap<>());
+ dbType = String.valueOf(database.getOrDefault("type", "sqlite"));
+ dbHost = String.valueOf(database.getOrDefault("host", "localhost"));
+ dbPort = Integer.parseInt(String.valueOf(database.getOrDefault("port", "3306")));
+ dbName = String.valueOf(database.getOrDefault("name", "velocitybroadcast"));
+ dbUser = String.valueOf(database.getOrDefault("user", "vb_user"));
+ dbPassword = String.valueOf(database.getOrDefault("password", "securepassword"));
if (shouldSave) {
- save(); // Update config with new version and preserve user values
+ save();
}
} catch (IOException e) {
@@ -82,26 +98,28 @@ public class ConfigHandler {
try {
Files.createDirectories(configPath.getParent());
- String editableSection = "";
- if (Files.exists(configPath)) {
- editableSection = Files.readAllLines(configPath).stream()
- .dropWhile(line -> !line.trim().equalsIgnoreCase("# ONLY EDIT BELOW THIS LINE"))
- .skip(1)
- .collect(Collectors.joining("\n"));
- }
+ Map general = new LinkedHashMap<>();
+ general.put("debug-messages-enabled", debugEnabled);
+ general.put("version-check-enabled", versionCheckEnabled);
+ general.put("prefix", prefix);
+
+ Map database = new LinkedHashMap<>();
+ database.put("type", dbType);
+ database.put("host", dbHost);
+ database.put("port", dbPort);
+ database.put("name", dbName);
+ database.put("user", dbUser);
+ database.put("password", dbPassword);
+
+ Map root = new LinkedHashMap<>();
+ root.put("general", general);
+ root.put("database", database);
try (BufferedWriter writer = Files.newBufferedWriter(configPath)) {
writer.write(VERSION_LINE + "\n\n");
- writer.write("# ONLY EDIT BELOW THIS LINE\n");
-
- if (!editableSection.isEmpty()) {
- writer.write(editableSection + "\n");
- } else {
- writer.write("debug-messages-enabled: false # Enables/disables debug messages (Default: false)\n");
- writer.write("version-check-enabled: true # Toggles version update messages for admins (Default: true)\n");
- writer.write("prefix: '&9&l[&3&lServer&9&l]&r ' # The prefix for broadcasts and messages\n");
- }
+ yaml.dump(root, writer);
}
+
} catch (IOException e) {
logger.error("Failed to save VelocityBroadcast config!", e);
}
@@ -127,4 +145,28 @@ public class ConfigHandler {
this.prefix = newPrefix;
save();
}
+
+ public String getDbType() {
+ return dbType;
+ }
+
+ public String getDbHost() {
+ return dbHost;
+ }
+
+ public int getDbPort() {
+ return dbPort;
+ }
+
+ public String getDbName() {
+ return dbName;
+ }
+
+ public String getDbUser() {
+ return dbUser;
+ }
+
+ public String getDbPassword() {
+ return dbPassword;
+ }
}
diff --git a/src/main/java/com/adzel/velocitybroadcast/LoginListener.java b/src/main/java/com/adzel/velocitybroadcast/LoginListener.java
new file mode 100644
index 0000000..eb61998
--- /dev/null
+++ b/src/main/java/com/adzel/velocitybroadcast/LoginListener.java
@@ -0,0 +1,50 @@
+package com.adzel.velocitybroadcast;
+
+import com.adzel.velocitybroadcast.util.DatabaseManager;
+import com.adzel.velocitybroadcast.util.UpdateChecker;
+import com.velocitypowered.api.event.Subscribe;
+import com.velocitypowered.api.event.connection.PostLoginEvent;
+import com.velocitypowered.api.proxy.Player;
+import com.velocitypowered.api.proxy.ProxyServer;
+
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.minimessage.MiniMessage;
+
+public class LoginListener {
+ private final ProxyServer server;
+ private final String currentVersion;
+ private final UpdateChecker updateChecker;
+ private final DatabaseManager databaseManager;
+
+ private static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage();
+
+ public LoginListener(ProxyServer server, String currentVersion, UpdateChecker updateChecker, DatabaseManager databaseManager) {
+ this.server = server;
+ this.currentVersion = currentVersion;
+ this.updateChecker = updateChecker;
+ this.databaseManager = databaseManager;
+ }
+
+ @Subscribe
+ public void onPlayerJoin(PostLoginEvent event) {
+ Player player = event.getPlayer();
+ if (player.hasPermission("vb.admin")) {
+ // ✅ Log admin join to DB
+ String serverName = server.getBoundAddress().toString(); // Optional
+ databaseManager.logAdminJoin(player.getUsername(), serverName);
+
+ // ✅ Notify if update is available
+ updateChecker.checkForUpdate().thenAccept(latest -> {
+ if (latest != null && !latest.equalsIgnoreCase(currentVersion)) {
+ Component message = MINI_MESSAGE.deserialize(
+ "[VelocityBroadcast] " +
+ "A new version is available: " +
+ "" + latest + " " +
+ "(You are on " + currentVersion + ")"
+ );
+ player.sendMessage(message);
+ }
+ });
+ }
+ }
+}
diff --git a/src/main/java/com/adzel/velocitybroadcast/UpdateChecker.java b/src/main/java/com/adzel/velocitybroadcast/UpdateChecker.java
new file mode 100644
index 0000000..d9b8892
--- /dev/null
+++ b/src/main/java/com/adzel/velocitybroadcast/UpdateChecker.java
@@ -0,0 +1,63 @@
+package com.adzel.velocitybroadcast.util;
+
+import com.velocitypowered.api.proxy.ProxyServer;
+import net.kyori.adventure.text.Component;
+import com.velocitypowered.api.proxy.Player;
+
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.concurrent.CompletableFuture;
+import java.util.logging.Logger;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+
+public class UpdateChecker {
+ private static final String ENDPOINT = "https://api.github.com/repos/AdzelFirestar/velocitybroadcast-reborn/releases/latest";
+ private final String currentVersion;
+ private final Logger logger;
+
+ public UpdateChecker(String currentVersion, Logger logger) {
+ this.currentVersion = currentVersion;
+ this.logger = logger;
+ }
+
+ public CompletableFuture checkForUpdate() {
+ return CompletableFuture.supplyAsync(() -> {
+ try {
+ HttpURLConnection connection = (HttpURLConnection) new URL(ENDPOINT).openConnection();
+ connection.setRequestProperty("Accept", "application/json");
+ connection.setConnectTimeout(3000);
+ connection.setReadTimeout(3000);
+
+ try (InputStreamReader reader = new InputStreamReader(connection.getInputStream())) {
+ JSONObject json = new JSONObject(new JSONTokener(reader));
+ String latestVersion = json.getString("tag_name").trim();
+
+ if (!latestVersion.equalsIgnoreCase(currentVersion)) {
+ logger.info("[VelocityBroadcast] Update available: " + latestVersion + " (you are on " + currentVersion + ")");
+ return latestVersion;
+ } else {
+ logger.info("[VelocityBroadcast] You are running the latest version (" + currentVersion + ").");
+ return null;
+ }
+ }
+ } catch (Exception e) {
+ logger.warning("[VelocityBroadcast] Failed to check for updates: " + e.getMessage());
+ return null;
+ }
+ });
+ }
+
+ public void notifyPlayerIfOutdated(ProxyServer server, String latestVersion) {
+ if (latestVersion != null && !latestVersion.equalsIgnoreCase(currentVersion)) {
+ String message = String.format("[VelocityBroadcast] A new version (%s) is available! You are running %s.", latestVersion, currentVersion);
+ Component component = Component.text(message);
+ for (Player player : server.getAllPlayers()) {
+ if (player.hasPermission("vb.admin")) {
+ player.sendMessage(component);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/adzel/velocitybroadcast/VBCommand.java b/src/main/java/com/adzel/velocitybroadcast/VBCommand.java
index eaddd1a..617c20b 100644
--- a/src/main/java/com/adzel/velocitybroadcast/VBCommand.java
+++ b/src/main/java/com/adzel/velocitybroadcast/VBCommand.java
@@ -2,8 +2,10 @@ package com.adzel.velocitybroadcast;
import java.util.List;
+import com.adzel.velocitybroadcast.util.DatabaseManager;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
+import com.velocitypowered.api.proxy.Player;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
@@ -11,10 +13,12 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
public class VBCommand implements SimpleCommand {
private final VelocityBroadcast plugin;
+ private final DatabaseManager databaseManager;
private final MiniMessage mm = MiniMessage.miniMessage();
public VBCommand(VelocityBroadcast plugin) {
this.plugin = plugin;
+ this.databaseManager = plugin.getDatabaseManager();
}
@Override
@@ -22,68 +26,91 @@ public class VBCommand implements SimpleCommand {
CommandSource source = invocation.source();
List args = List.of(invocation.arguments());
- if (args.isEmpty() || args.get(0).equalsIgnoreCase("help")) {
- source.sendMessage(parseFormatted("VelocityBroadcast Commands:"));
- source.sendMessage(parseFormatted("/vb - Broadcast a message to all players"));
+ String fullCommand = "/vb" + (args.isEmpty() ? "" : " " + String.join(" ", args));
+ String username = (source instanceof Player) ? ((Player) source).getUsername() : "Console";
- if (source.hasPermission("vb.admin")) {
- source.sendMessage(parseFormatted("/vb prefix - Change the broadcast prefix"));
- source.sendMessage(parseFormatted("/vb reload - Reload the plugin config"));
+ boolean success = true;
+
+ try {
+ if (args.isEmpty() || args.get(0).equalsIgnoreCase("help")) {
+ source.sendMessage(parseFormatted("VelocityBroadcast Commands:"));
+ source.sendMessage(parseFormatted("/vb - Broadcast a message to all players"));
+
+ if (source.hasPermission("vb.admin")) {
+ source.sendMessage(parseFormatted("/vb prefix - Change the broadcast prefix"));
+ source.sendMessage(parseFormatted("/vb reload - Reload the plugin config"));
+ }
+
+ success = false;
+ return;
}
- return;
- }
- String sub = args.get(0).toLowerCase();
- List subArgs = args.subList(1, args.size());
+ String sub = args.get(0).toLowerCase();
+ List subArgs = args.subList(1, args.size());
- switch (sub) {
- case "prefix":
- if (!source.hasPermission("vb.admin")) {
- source.sendMessage(parseFormatted("You don't have permission to change the broadcast prefix."));
- return;
+ switch (sub) {
+ case "prefix" -> {
+ if (!source.hasPermission("vb.admin")) {
+ source.sendMessage(parseFormatted("You don't have permission to change the broadcast prefix."));
+ success = false;
+ return;
+ }
+
+ if (subArgs.isEmpty()) {
+ source.sendMessage(parseFormatted("Usage: /vb prefix "));
+ success = false;
+ return;
+ }
+
+ String newPrefix = String.join(" ", subArgs);
+ plugin.getConfigHandler().setPrefix(newPrefix);
+ source.sendMessage(parseFormatted("Prefix updated to: " + newPrefix + ""));
+
+ if (plugin.getConfigHandler().isDebugEnabled()) {
+ plugin.getLogger().info("[Prefix] Updated prefix to: " + newPrefix);
+ }
}
- if (subArgs.isEmpty()) {
- source.sendMessage(parseFormatted("Usage: /vb prefix "));
- return;
+ case "reload" -> {
+ if (!source.hasPermission("vb.admin")) {
+ source.sendMessage(parseFormatted("You don't have permission to reload the config."));
+ success = false;
+ return;
+ }
+
+ plugin.getConfigHandler().reload();
+ source.sendMessage(parseFormatted("VelocityBroadcast config reloaded."));
+
+ if (plugin.getConfigHandler().isDebugEnabled()) {
+ plugin.getLogger().info("[Reload] Config reloaded by " + source.toString());
+ }
}
- String newPrefix = String.join(" ", subArgs);
- plugin.getConfigHandler().setPrefix(newPrefix);
- source.sendMessage(parseFormatted("Prefix updated to: " + newPrefix + ""));
- if (plugin.getConfigHandler().isDebugEnabled()) {
- plugin.getLogger().info("[Prefix] Updated prefix to: " + newPrefix);
- }
- break;
+ default -> {
+ // Treat as broadcast message
+ if (!source.hasPermission("vb.broadcast")) {
+ source.sendMessage(parseFormatted("You don't have permission to broadcast."));
+ success = false;
+ return;
+ }
- case "reload":
- if (!source.hasPermission("vb.admin")) {
- source.sendMessage(parseFormatted("You don't have permission to reload the config."));
- return;
- }
+ String fullMessage = plugin.getConfigHandler().getPrefix() + String.join(" ", args);
+ Component broadcast = parseFormatted(fullMessage);
- plugin.getConfigHandler().reload();
- source.sendMessage(parseFormatted("VelocityBroadcast config reloaded."));
- if (plugin.getConfigHandler().isDebugEnabled()) {
- plugin.getLogger().info("[Reload] Config reloaded by " + source.toString());
- }
- break;
+ plugin.getServer().getAllPlayers().forEach(p -> p.sendMessage(broadcast));
- default:
- // Treat as broadcast message
- if (!source.hasPermission("vb.broadcast")) {
- source.sendMessage(parseFormatted("You don't have permission to broadcast."));
- return;
+ if (plugin.getConfigHandler().isDebugEnabled()) {
+ plugin.getLogger().info("[Broadcast] Sent: " + fullMessage);
+ }
}
-
- String fullMessage = plugin.getConfigHandler().getPrefix() + String.join(" ", args);
- Component broadcast = parseFormatted(fullMessage);
- plugin.getServer().getAllPlayers().forEach(p -> p.sendMessage(broadcast));
-
- if (plugin.getConfigHandler().isDebugEnabled()) {
- plugin.getLogger().info("[Broadcast] Sent: " + fullMessage);
- }
- break;
+ }
+ } catch (Exception e) {
+ plugin.getLogger().error("Error executing /vb command", e);
+ source.sendMessage(parseFormatted("An error occurred while executing the command."));
+ success = false;
+ } finally {
+ // ✅ Log the command usage
+ databaseManager.logCommand(username, fullCommand, success);
}
}
diff --git a/src/main/java/com/adzel/velocitybroadcast/VelocityBroadcast.java b/src/main/java/com/adzel/velocitybroadcast/VelocityBroadcast.java
index e11f208..857df2f 100644
--- a/src/main/java/com/adzel/velocitybroadcast/VelocityBroadcast.java
+++ b/src/main/java/com/adzel/velocitybroadcast/VelocityBroadcast.java
@@ -4,6 +4,8 @@ import java.nio.file.Path;
import org.slf4j.Logger;
+import com.adzel.velocitybroadcast.util.DatabaseManager;
+import com.adzel.velocitybroadcast.util.UpdateChecker;
import com.google.inject.Inject;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe;
@@ -18,19 +20,21 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
@Plugin(
id = "velocitybroadcast",
name = "VelocityBroadcast",
- version = "0.2-pre",
+ version = "0.3-pre",
description = "A proxy-wide broadcast plugin for Velocity.",
authors = {"Adzel"}
)
public class VelocityBroadcast {
- public static final String PLUGIN_VERSION = "0.2-pre";
+ public static final String PLUGIN_VERSION = "0.3-pre";
public static final MiniMessage MINI_MESSAGE = MiniMessage.miniMessage();
private final ProxyServer server;
private final Logger logger;
private final Path dataDirectory;
+
private ConfigHandler config;
+ private DatabaseManager databaseManager;
@Inject
public VelocityBroadcast(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
@@ -49,7 +53,25 @@ public class VelocityBroadcast {
logger.info("[VelocityBroadcast] Debug mode is enabled.");
}
- // Register the root /vb command handler
+ // Initialize database manager
+ java.util.logging.Logger jdkLogger = java.util.logging.Logger.getLogger("VelocityBroadcast");
+ this.databaseManager = new DatabaseManager(config, jdkLogger, dataDirectory);
+ databaseManager.initialize();
+
+ // Check for updates (async)
+ UpdateChecker updateChecker = new UpdateChecker(PLUGIN_VERSION, jdkLogger);
+ updateChecker.checkForUpdate().thenAccept(latest -> {
+ if (latest != null) {
+ logger.warn("[VelocityBroadcast] A new version is available: " + latest + " (You are on " + PLUGIN_VERSION + ")");
+ } else {
+ logger.info("[VelocityBroadcast] You are running the latest version (" + PLUGIN_VERSION + ").");
+ }
+ });
+
+ // ✅ Register login listener with DatabaseManager
+ server.getEventManager().register(this, new LoginListener(server, PLUGIN_VERSION, updateChecker, databaseManager));
+
+ // Register root command
server.getCommandManager().register(
server.getCommandManager().metaBuilder("vb").plugin(this).build(),
new VBCommand(this)
@@ -78,4 +100,8 @@ public class VelocityBroadcast {
public ConfigHandler getConfigHandler() {
return config;
}
+
+ public DatabaseManager getDatabaseManager() {
+ return databaseManager;
+ }
}
diff --git a/src/main/java/com/adzel/velocitybroadcast/util/DatabaseManager.java b/src/main/java/com/adzel/velocitybroadcast/util/DatabaseManager.java
new file mode 100644
index 0000000..dc1a5be
--- /dev/null
+++ b/src/main/java/com/adzel/velocitybroadcast/util/DatabaseManager.java
@@ -0,0 +1,127 @@
+package com.adzel.velocitybroadcast.util;
+
+import java.nio.file.Path;
+import java.sql.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.logging.Logger;
+
+import com.adzel.velocitybroadcast.ConfigHandler;
+
+public class DatabaseManager {
+ private final Logger logger;
+ private final ConfigHandler config;
+ private final Path dataDirectory;
+ private Connection connection;
+ private final ExecutorService executor = Executors.newSingleThreadExecutor();
+
+ public DatabaseManager(ConfigHandler config, Logger logger, Path dataDirectory) {
+ this.config = config;
+ this.logger = logger;
+ this.dataDirectory = dataDirectory;
+ }
+
+ public void initialize() {
+ try {
+ if (config.getDbType().equalsIgnoreCase("mysql")) {
+ Class.forName("com.mysql.cj.jdbc.Driver");
+ connection = DriverManager.getConnection(
+ "jdbc:mysql://" + config.getDbHost() + ":" + config.getDbPort() + "/" + config.getDbName() + "?useSSL=false&autoReconnect=true",
+ config.getDbUser(),
+ config.getDbPassword()
+ );
+ } else {
+ Class.forName("org.sqlite.JDBC");
+ Path dbFile = dataDirectory.resolve(config.getDbName() + ".db");
+ connection = DriverManager.getConnection("jdbc:sqlite:" + dbFile.toAbsolutePath());
+ }
+
+ logger.info("[VelocityBroadcast] Connected to " + config.getDbType().toUpperCase() + " database.");
+ initializeTables();
+
+ } catch (Exception e) {
+ logger.warning("[VelocityBroadcast] Failed to connect to database: " + e.getMessage());
+ }
+ }
+
+ private void initializeTables() {
+ boolean isMySQL = config.getDbType().equalsIgnoreCase("mysql");
+ String idSyntax = isMySQL ? "INT AUTO_INCREMENT PRIMARY KEY" : "INTEGER PRIMARY KEY AUTOINCREMENT";
+
+ String broadcastTable = "CREATE TABLE IF NOT EXISTS vb_broadcast_logs (" +
+ "id " + idSyntax + "," +
+ "timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," +
+ "sender VARCHAR(64) NOT NULL," +
+ "message TEXT NOT NULL," +
+ "source_server VARCHAR(64)" +
+ ");";
+
+ String commandTable = "CREATE TABLE IF NOT EXISTS vb_command_logs (" +
+ "id " + idSyntax + "," +
+ "timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," +
+ "user VARCHAR(64) NOT NULL," +
+ "command TEXT NOT NULL," +
+ "success BOOLEAN" +
+ ");";
+
+ String joinTable = "CREATE TABLE IF NOT EXISTS vb_admin_joins (" +
+ "id " + idSyntax + "," +
+ "timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," +
+ "username VARCHAR(64) NOT NULL," +
+ "server VARCHAR(64)" +
+ ");";
+
+ executeUpdate(broadcastTable);
+ executeUpdate(commandTable);
+ executeUpdate(joinTable);
+ }
+
+ public void logBroadcast(String sender, String message, String sourceServer) {
+ String sql = "INSERT INTO vb_broadcast_logs (sender, message, source_server) VALUES (?, ?, ?)";
+ executeAsync(sql, sender, message, sourceServer);
+ }
+
+ public void logCommand(String user, String command, boolean success) {
+ String sql = "INSERT INTO vb_command_logs (user, command, success) VALUES (?, ?, ?)";
+ executeAsync(sql, user, command, success);
+ }
+
+ public void logAdminJoin(String username, String serverName) {
+ String sql = "INSERT INTO vb_admin_joins (username, server) VALUES (?, ?)";
+ executeAsync(sql, username, serverName);
+ }
+
+ private void executeAsync(String sql, Object... params) {
+ executor.submit(() -> {
+ try (PreparedStatement stmt = connection.prepareStatement(sql)) {
+ for (int i = 0; i < params.length; i++) {
+ stmt.setObject(i + 1, params[i]);
+ }
+ stmt.executeUpdate();
+ } catch (SQLException e) {
+ logger.warning("[VelocityBroadcast] Database query failed: " + e.getMessage());
+ }
+ });
+ }
+
+ private void executeUpdate(String sql) {
+ executor.submit(() -> {
+ try (Statement stmt = connection.createStatement()) {
+ stmt.executeUpdate(sql);
+ } catch (SQLException e) {
+ logger.warning("[VelocityBroadcast] Failed to initialize table: " + e.getMessage());
+ }
+ });
+ }
+
+ public void close() {
+ try {
+ if (connection != null && !connection.isClosed()) {
+ connection.close();
+ executor.shutdown();
+ }
+ } catch (SQLException e) {
+ logger.warning("[VelocityBroadcast] Failed to close database: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/main/resources/plugin.json b/src/main/resources/plugin.json
index d071f91..484681b 100644
--- a/src/main/resources/plugin.json
+++ b/src/main/resources/plugin.json
@@ -1,7 +1,7 @@
{
"id": "velocitybroadcast",
"name": "VelocityBroadcast",
- "version": "0.2-pre",
+ "version": "0.3-pre",
"authors": ["Adzel"],
"main": "com.adzel.velocitybroadcast.VelocityBroadcast",
"description": "A proxy-wide broadcast plugin for Velocity.",
diff --git a/target/classes/plugin.json b/target/classes/plugin.json
index d071f91..484681b 100644
--- a/target/classes/plugin.json
+++ b/target/classes/plugin.json
@@ -1,7 +1,7 @@
{
"id": "velocitybroadcast",
"name": "VelocityBroadcast",
- "version": "0.2-pre",
+ "version": "0.3-pre",
"authors": ["Adzel"],
"main": "com.adzel.velocitybroadcast.VelocityBroadcast",
"description": "A proxy-wide broadcast plugin for Velocity.",
diff --git a/target/classes/velocity-plugin.json b/target/classes/velocity-plugin.json
index 31be600..081c28b 100644
--- a/target/classes/velocity-plugin.json
+++ b/target/classes/velocity-plugin.json
@@ -1 +1 @@
-{"id":"velocitybroadcast","name":"VelocityBroadcast","version":"0.2-pre","description":"A proxy-wide broadcast plugin for Velocity.","authors":["Adzel"],"dependencies":[],"main":"com.adzel.velocitybroadcast.VelocityBroadcast"}
\ No newline at end of file
+{"id":"velocitybroadcast","name":"VelocityBroadcast","version":"0.3-pre","description":"A proxy-wide broadcast plugin for Velocity.","authors":["Adzel"],"dependencies":[],"main":"com.adzel.velocitybroadcast.VelocityBroadcast"}
\ No newline at end of file
diff --git a/target/maven-archiver/pom.properties b/target/maven-archiver/pom.properties
index 5b954b7..663f2ed 100644
--- a/target/maven-archiver/pom.properties
+++ b/target/maven-archiver/pom.properties
@@ -1,3 +1,3 @@
artifactId=velocitybroadcast
groupId=com.adzel.velocitybroadcast
-version=0.2-pre
+version=0.3-pre
diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
index fe04c2a..abe6263 100644
--- a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
+++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
@@ -4,4 +4,7 @@ com\adzel\velocitybroadcast\BroadcastCommand.class
com\adzel\velocitybroadcast\ConfigHandler.class
com\adzel\velocitybroadcast\ReloadCommand.class
velocity-plugin.json
+com\adzel\velocitybroadcast\util\DatabaseManager.class
com\adzel\velocitybroadcast\PrefixCommand.class
+com\adzel\velocitybroadcast\util\UpdateChecker.class
+com\adzel\velocitybroadcast\LoginListener.class
diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
index f3d21d8..689ac39 100644
--- a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
+++ b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
@@ -2,5 +2,8 @@ C:\Users\theon\OneDrive\Desktop\VelocityBroadcast\src\main\java\com\adzel\veloci
C:\Users\theon\OneDrive\Desktop\VelocityBroadcast\src\main\java\com\adzel\velocitybroadcast\ReloadCommand.java
C:\Users\theon\OneDrive\Desktop\VelocityBroadcast\src\main\java\com\adzel\velocitybroadcast\BroadcastCommand.java
C:\Users\theon\OneDrive\Desktop\VelocityBroadcast\src\main\java\com\adzel\velocitybroadcast\ConfigHandler.java
+C:\Users\theon\OneDrive\Desktop\VelocityBroadcast\src\main\java\com\adzel\velocitybroadcast\UpdateChecker.java
+C:\Users\theon\OneDrive\Desktop\VelocityBroadcast\src\main\java\com\adzel\velocitybroadcast\util\DatabaseManager.java
+C:\Users\theon\OneDrive\Desktop\VelocityBroadcast\src\main\java\com\adzel\velocitybroadcast\LoginListener.java
C:\Users\theon\OneDrive\Desktop\VelocityBroadcast\src\main\java\com\adzel\velocitybroadcast\VelocityBroadcast.java
C:\Users\theon\OneDrive\Desktop\VelocityBroadcast\src\main\java\com\adzel\velocitybroadcast\PrefixCommand.java