Uploading update source code for version 0.3.7

This commit is contained in:
2025-11-13 17:53:54 -08:00
parent d9c89504fb
commit f6d8e26e1d
23 changed files with 1161 additions and 1341 deletions

View File

@@ -1,58 +1,58 @@
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;
public class BroadcastCommand implements SimpleCommand {
private final VelocityBroadcast plugin;
private final DatabaseManager databaseManager;
private final MiniMessage mm = MiniMessage.miniMessage();
public BroadcastCommand(VelocityBroadcast plugin) {
this.plugin = plugin;
this.databaseManager = plugin.getDatabaseManager();
}
@Override
public void execute(Invocation invocation) {
CommandSource source = invocation.source();
List<String> args = List.of(invocation.arguments());
if (!source.hasPermission("vb.broadcast")) {
source.sendMessage(mm.deserialize("<red>You don't have permission to use this command.</red>"));
return;
}
if (args.isEmpty()) {
source.sendMessage(mm.deserialize("<red>Usage: /vb <message></red>"));
return;
}
String messageRaw = String.join(" ", args);
String prefix = plugin.getConfigHandler().getPrefix();
String fullMessage = prefix + messageRaw;
Component broadcast = mm.deserialize(fullMessage);
plugin.getServer().getAllPlayers().forEach(player -> player.sendMessage(broadcast));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Broadcast] Sent: " + fullMessage);
}
// ✅ Log to the database with proper sender
String sender = (source instanceof Player player) ? player.getUsername() : "Console";
String sourceServer = plugin.getServer().getBoundAddress().toString();
databaseManager.logBroadcast(sender, messageRaw, sourceServer);
// Optional feedback to source
source.sendMessage(mm.deserialize("<green>Broadcast sent.</green>"));
}
}
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;
public class BroadcastCommand implements SimpleCommand {
private final VelocityBroadcast plugin;
private final DatabaseManager databaseManager;
private final MiniMessage mm = MiniMessage.miniMessage();
public BroadcastCommand(VelocityBroadcast plugin) {
this.plugin = plugin;
this.databaseManager = plugin.getDatabaseManager();
}
@Override
public void execute(Invocation invocation) {
CommandSource source = invocation.source();
List<String> args = List.of(invocation.arguments());
if (!source.hasPermission("vb.broadcast")) {
source.sendMessage(mm.deserialize("<red>You don't have permission to use this command.</red>"));
return;
}
if (args.isEmpty()) {
source.sendMessage(mm.deserialize("<red>Usage: /vb <message></red>"));
return;
}
String messageRaw = String.join(" ", args);
String prefix = plugin.getConfigHandler().getPrefix();
String fullMessage = prefix + messageRaw;
Component broadcast = mm.deserialize(fullMessage);
plugin.getServer().getAllPlayers().forEach(player -> player.sendMessage(broadcast));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Broadcast] Sent: " + fullMessage);
}
// ✅ Log to the database with proper sender
String sender = (source instanceof Player player) ? player.getUsername() : "Console";
String sourceServer = plugin.getServer().getBoundAddress().toString();
databaseManager.logBroadcast(sender, messageRaw, sourceServer);
// Optional feedback to source
source.sendMessage(mm.deserialize("<green>Broadcast sent.</green>"));
}
}

View File

@@ -1,172 +1,172 @@
package com.adzel.velocitybroadcast;
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.Map;
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;
private final Logger logger;
private boolean debugEnabled = false;
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());
boolean shouldSave = false;
if (!Files.exists(configPath)) {
save();
return;
}
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;
}
Map<String, Object> root = yaml.load(Files.newBufferedReader(configPath));
if (root == null) root = new LinkedHashMap<>();
Map<String, Object> general = (Map<String, Object>) 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<String, Object> database = (Map<String, Object>) 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();
}
} catch (IOException e) {
logger.error("Failed to load VelocityBroadcast config!", e);
}
}
public void save() {
try {
Files.createDirectories(configPath.getParent());
Map<String, Object> general = new LinkedHashMap<>();
general.put("debug-messages-enabled", debugEnabled);
general.put("version-check-enabled", versionCheckEnabled);
general.put("prefix", prefix);
Map<String, Object> 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<String, Object> root = new LinkedHashMap<>();
root.put("general", general);
root.put("database", database);
try (BufferedWriter writer = Files.newBufferedWriter(configPath)) {
writer.write(VERSION_LINE + "\n\n");
yaml.dump(root, writer);
}
} catch (IOException e) {
logger.error("Failed to save VelocityBroadcast config!", e);
}
}
public void reload() {
load();
}
public boolean isDebugEnabled() {
return debugEnabled;
}
public boolean isVersionCheckEnabled() {
return versionCheckEnabled;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String newPrefix) {
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;
}
}
package com.adzel.velocitybroadcast;
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.Map;
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;
private final Logger logger;
private boolean debugEnabled = false;
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());
boolean shouldSave = false;
if (!Files.exists(configPath)) {
save();
return;
}
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;
}
Map<String, Object> root = yaml.load(Files.newBufferedReader(configPath));
if (root == null) root = new LinkedHashMap<>();
Map<String, Object> general = (Map<String, Object>) 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<String, Object> database = (Map<String, Object>) 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();
}
} catch (IOException e) {
logger.error("Failed to load VelocityBroadcast config!", e);
}
}
public void save() {
try {
Files.createDirectories(configPath.getParent());
Map<String, Object> general = new LinkedHashMap<>();
general.put("debug-messages-enabled", debugEnabled);
general.put("version-check-enabled", versionCheckEnabled);
general.put("prefix", prefix);
Map<String, Object> 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<String, Object> root = new LinkedHashMap<>();
root.put("general", general);
root.put("database", database);
try (BufferedWriter writer = Files.newBufferedWriter(configPath)) {
writer.write(VERSION_LINE + "\n\n");
yaml.dump(root, writer);
}
} catch (IOException e) {
logger.error("Failed to save VelocityBroadcast config!", e);
}
}
public void reload() {
load();
}
public boolean isDebugEnabled() {
return debugEnabled;
}
public boolean isVersionCheckEnabled() {
return versionCheckEnabled;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String newPrefix) {
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;
}
}

View File

@@ -1,50 +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(
"<bold><gold>[VelocityBroadcast]</gold></bold> " +
"<gradient:yellow:red>A new version is available: </gradient:yellow:red>" +
"<bold><green>" + latest + "</green></bold> " +
"<gray>(You are on <red>" + currentVersion + "</red>)</gray>"
);
player.sendMessage(message);
}
});
}
}
}
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(
"<bold><gold>[VelocityBroadcast]</gold></bold> " +
"<gradient:yellow:red>A new version is available: </gradient:yellow:red>" +
"<bold><green>" + latest + "</green></bold> " +
"<gray>(You are on <red>" + currentVersion + "</red>)</gray>"
);
player.sendMessage(message);
}
});
}
}
}

View File

@@ -1,44 +1,44 @@
package com.adzel.velocitybroadcast;
import java.util.List;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import net.kyori.adventure.text.minimessage.MiniMessage;
public class PrefixCommand implements SimpleCommand {
private final VelocityBroadcast plugin;
public PrefixCommand(VelocityBroadcast plugin) {
this.plugin = plugin;
}
@Override
public void execute(Invocation invocation) {
CommandSource source = invocation.source();
List<String> args = List.of(invocation.arguments());
if (!source.hasPermission("vb.admin")) {
source.sendMessage(MiniMessage.miniMessage().deserialize("<red>You don't have permission to change the broadcast prefix.</red>"));
return;
}
if (args.isEmpty()) {
source.sendMessage(MiniMessage.miniMessage().deserialize("<red>Usage: /vb prefix <newPrefix></red>"));
return;
}
String newPrefix = String.join(" ", args);
plugin.getConfigHandler().setPrefix(newPrefix);
source.sendMessage(MiniMessage.miniMessage().deserialize(
"<green>Broadcast prefix updated to:</green> <gray>" + newPrefix + "</gray>"
));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Prefix] Updated prefix to: " + newPrefix);
}
}
}
package com.adzel.velocitybroadcast;
import java.util.List;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import net.kyori.adventure.text.minimessage.MiniMessage;
public class PrefixCommand implements SimpleCommand {
private final VelocityBroadcast plugin;
public PrefixCommand(VelocityBroadcast plugin) {
this.plugin = plugin;
}
@Override
public void execute(Invocation invocation) {
CommandSource source = invocation.source();
List<String> args = List.of(invocation.arguments());
if (!source.hasPermission("vb.admin")) {
source.sendMessage(MiniMessage.miniMessage().deserialize("<red>You don't have permission to change the broadcast prefix.</red>"));
return;
}
if (args.isEmpty()) {
source.sendMessage(MiniMessage.miniMessage().deserialize("<red>Usage: /vb prefix <newPrefix></red>"));
return;
}
String newPrefix = String.join(" ", args);
plugin.getConfigHandler().setPrefix(newPrefix);
source.sendMessage(MiniMessage.miniMessage().deserialize(
"<green>Broadcast prefix updated to:</green> <gray>" + newPrefix + "</gray>"
));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Prefix] Updated prefix to: " + newPrefix);
}
}
}

View File

@@ -1,33 +1,33 @@
package com.adzel.velocitybroadcast;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import net.kyori.adventure.text.minimessage.MiniMessage;
import java.util.List;
public class ReloadCommand implements SimpleCommand {
private final VelocityBroadcast plugin;
public ReloadCommand(VelocityBroadcast plugin) {
this.plugin = plugin;
}
@Override
public void execute(Invocation invocation) {
CommandSource source = invocation.source();
if (!source.hasPermission("vb.admin")) {
source.sendMessage(MiniMessage.miniMessage().deserialize("<red>You don't have permission to reload the config.</red>"));
return;
}
plugin.getConfigHandler().reload();
source.sendMessage(MiniMessage.miniMessage().deserialize("<green>VelocityBroadcast config reloaded.</green>"));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Reload] Config reloaded by " + source.toString());
}
}
}
package com.adzel.velocitybroadcast;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.SimpleCommand;
import net.kyori.adventure.text.minimessage.MiniMessage;
import java.util.List;
public class ReloadCommand implements SimpleCommand {
private final VelocityBroadcast plugin;
public ReloadCommand(VelocityBroadcast plugin) {
this.plugin = plugin;
}
@Override
public void execute(Invocation invocation) {
CommandSource source = invocation.source();
if (!source.hasPermission("vb.admin")) {
source.sendMessage(MiniMessage.miniMessage().deserialize("<red>You don't have permission to reload the config.</red>"));
return;
}
plugin.getConfigHandler().reload();
source.sendMessage(MiniMessage.miniMessage().deserialize("<green>VelocityBroadcast config reloaded.</green>"));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Reload] Config reloaded by " + source.toString());
}
}
}

View File

@@ -1,63 +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<String> 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);
}
}
}
}
}
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://git.addydevelops.site/api/v1/repos/Adzel/Velocity-Broadcast-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<String> 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);
}
}
}
}
}

View File

@@ -1,143 +1,143 @@
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;
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
public void execute(Invocation invocation) {
CommandSource source = invocation.source();
List<String> args = List.of(invocation.arguments());
String fullCommand = "/vb" + (args.isEmpty() ? "" : " " + String.join(" ", args));
String username = (source instanceof Player) ? ((Player) source).getUsername() : "Console";
boolean success = true;
try {
if (args.isEmpty() || args.get(0).equalsIgnoreCase("help")) {
source.sendMessage(parseFormatted("<gold><bold>VelocityBroadcast Commands:</bold></gold>"));
source.sendMessage(parseFormatted("<yellow>/vb <message></yellow> <gray>- Broadcast a message to all players</gray>"));
if (source.hasPermission("vb.admin")) {
source.sendMessage(parseFormatted("<yellow>/vb prefix <newPrefix></yellow> <gray>- Change the broadcast prefix</gray>"));
source.sendMessage(parseFormatted("<yellow>/vb reload</yellow> <gray>- Reload the plugin config</gray>"));
}
success = false;
return;
}
String sub = args.get(0).toLowerCase();
List<String> subArgs = args.subList(1, args.size());
switch (sub) {
case "prefix" -> {
if (!source.hasPermission("vb.admin")) {
source.sendMessage(parseFormatted("<red>You don't have permission to change the broadcast prefix.</red>"));
success = false;
return;
}
if (subArgs.isEmpty()) {
source.sendMessage(parseFormatted("<red>Usage: /vb prefix <newPrefix></red>"));
success = false;
return;
}
String newPrefix = String.join(" ", subArgs);
plugin.getConfigHandler().setPrefix(newPrefix);
source.sendMessage(parseFormatted("<green>Prefix updated to:</green> <gray>" + newPrefix + "</gray>"));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Prefix] Updated prefix to: " + newPrefix);
}
}
case "reload" -> {
if (!source.hasPermission("vb.admin")) {
source.sendMessage(parseFormatted("<red>You don't have permission to reload the config.</red>"));
success = false;
return;
}
plugin.getConfigHandler().reload();
source.sendMessage(parseFormatted("<green>VelocityBroadcast config reloaded.</green>"));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Reload] Config reloaded by " + source.toString());
}
}
default -> {
// Treat as broadcast message
if (!source.hasPermission("vb.broadcast")) {
source.sendMessage(parseFormatted("<red>You don't have permission to broadcast.</red>"));
success = false;
return;
}
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);
}
}
}
} catch (Exception e) {
plugin.getLogger().error("Error executing /vb command", e);
source.sendMessage(parseFormatted("<red>An error occurred while executing the command.</red>"));
success = false;
} finally {
// ✅ Log the command usage
databaseManager.logCommand(username, fullCommand, success);
}
}
private Component parseFormatted(String input) {
String mini = input
.replace("&0", "<black>")
.replace("&1", "<dark_blue>")
.replace("&2", "<dark_green>")
.replace("&3", "<dark_aqua>")
.replace("&4", "<dark_red>")
.replace("&5", "<dark_purple>")
.replace("&6", "<gold>")
.replace("&7", "<gray>")
.replace("&8", "<dark_gray>")
.replace("&9", "<blue>")
.replace("&a", "<green>")
.replace("&b", "<aqua>")
.replace("&c", "<red>")
.replace("&d", "<light_purple>")
.replace("&e", "<yellow>")
.replace("&f", "<white>")
.replace("&l", "<bold>")
.replace("&n", "<underlined>")
.replace("&o", "<italic>")
.replace("&m", "<strikethrough>")
.replace("&r", "<reset>");
return mm.deserialize(mini);
}
}
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;
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
public void execute(Invocation invocation) {
CommandSource source = invocation.source();
List<String> args = List.of(invocation.arguments());
String fullCommand = "/vb" + (args.isEmpty() ? "" : " " + String.join(" ", args));
String username = (source instanceof Player) ? ((Player) source).getUsername() : "Console";
boolean success = true;
try {
if (args.isEmpty() || args.get(0).equalsIgnoreCase("help")) {
source.sendMessage(parseFormatted("<gold><bold>VelocityBroadcast Commands:</bold></gold>"));
source.sendMessage(parseFormatted("<yellow>/vb <message></yellow> <gray>- Broadcast a message to all players</gray>"));
if (source.hasPermission("vb.admin")) {
source.sendMessage(parseFormatted("<yellow>/vb prefix <newPrefix></yellow> <gray>- Change the broadcast prefix</gray>"));
source.sendMessage(parseFormatted("<yellow>/vb reload</yellow> <gray>- Reload the plugin config</gray>"));
}
success = false;
return;
}
String sub = args.get(0).toLowerCase();
List<String> subArgs = args.subList(1, args.size());
switch (sub) {
case "prefix" -> {
if (!source.hasPermission("vb.admin")) {
source.sendMessage(parseFormatted("<red>You don't have permission to change the broadcast prefix.</red>"));
success = false;
return;
}
if (subArgs.isEmpty()) {
source.sendMessage(parseFormatted("<red>Usage: /vb prefix <newPrefix></red>"));
success = false;
return;
}
String newPrefix = String.join(" ", subArgs);
plugin.getConfigHandler().setPrefix(newPrefix);
source.sendMessage(parseFormatted("<green>Prefix updated to:</green> <gray>" + newPrefix + "</gray>"));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Prefix] Updated prefix to: " + newPrefix);
}
}
case "reload" -> {
if (!source.hasPermission("vb.admin")) {
source.sendMessage(parseFormatted("<red>You don't have permission to reload the config.</red>"));
success = false;
return;
}
plugin.getConfigHandler().reload();
source.sendMessage(parseFormatted("<green>VelocityBroadcast config reloaded.</green>"));
if (plugin.getConfigHandler().isDebugEnabled()) {
plugin.getLogger().info("[Reload] Config reloaded by " + source.toString());
}
}
default -> {
// Treat as broadcast message
if (!source.hasPermission("vb.broadcast")) {
source.sendMessage(parseFormatted("<red>You don't have permission to broadcast.</red>"));
success = false;
return;
}
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);
}
}
}
} catch (Exception e) {
plugin.getLogger().error("Error executing /vb command", e);
source.sendMessage(parseFormatted("<red>An error occurred while executing the command.</red>"));
success = false;
} finally {
// ✅ Log the command usage
databaseManager.logCommand(username, fullCommand, success);
}
}
private Component parseFormatted(String input) {
String mini = input
.replace("&0", "<black>")
.replace("&1", "<dark_blue>")
.replace("&2", "<dark_green>")
.replace("&3", "<dark_aqua>")
.replace("&4", "<dark_red>")
.replace("&5", "<dark_purple>")
.replace("&6", "<gold>")
.replace("&7", "<gray>")
.replace("&8", "<dark_gray>")
.replace("&9", "<blue>")
.replace("&a", "<green>")
.replace("&b", "<aqua>")
.replace("&c", "<red>")
.replace("&d", "<light_purple>")
.replace("&e", "<yellow>")
.replace("&f", "<white>")
.replace("&l", "<bold>")
.replace("&n", "<underlined>")
.replace("&o", "<italic>")
.replace("&m", "<strikethrough>")
.replace("&r", "<reset>");
return mm.deserialize(mini);
}
}

View File

@@ -1,123 +1,123 @@
package com.adzel.velocitybroadcast;
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;
import com.velocitypowered.api.event.connection.LoginEvent;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
@Plugin(
id = "velocitybroadcast",
name = "VelocityBroadcast",
version = "0.3.5",
description = "A proxy-wide broadcast plugin for Velocity.",
authors = {"Adzel"}
)
public class VelocityBroadcast {
public static final String PLUGIN_VERSION = "0.3.5";
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;
private LuckPerms luckPerms;
@Inject
public VelocityBroadcast(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
this.server = server;
this.logger = logger;
this.dataDirectory = dataDirectory;
}
@Subscribe(order = PostOrder.EARLY)
public void onProxyInitialization(ProxyInitializeEvent event) {
// Load config
this.config = new ConfigHandler(dataDirectory.resolve("config.yml"), logger);
config.load();
if (config.isDebugEnabled()) {
logger.info("[VelocityBroadcast] Debug mode is enabled.");
}
// Initialize LuckPerms
try {
this.luckPerms = LuckPermsProvider.get();
logger.info("[VelocityBroadcast] Successfully hooked into LuckPerms.");
} catch (IllegalStateException e) {
logger.error("[VelocityBroadcast] LuckPerms is not loaded! This plugin requires LuckPerms.");
return; // Prevent plugin from loading if LP is not available
}
// 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
server.getEventManager().register(this, new LoginListener(server, PLUGIN_VERSION, updateChecker, databaseManager));
// Register command
server.getCommandManager().register(
server.getCommandManager().metaBuilder("vb").plugin(this).build(),
new VBCommand(this)
);
logger.info("[VelocityBroadcast] Loaded VelocityBroadcast v" + PLUGIN_VERSION);
}
@Subscribe
public void onLogin(LoginEvent event) {
if (event.getPlayer().hasPermission("vb.admin") && config.isVersionCheckEnabled()) {
event.getPlayer().sendMessage(
MINI_MESSAGE.deserialize("<yellow>[VelocityBroadcast] You're running version " + PLUGIN_VERSION + ".</yellow>")
);
}
}
public ProxyServer getServer() {
return server;
}
public Logger getLogger() {
return logger;
}
public ConfigHandler getConfigHandler() {
return config;
}
public DatabaseManager getDatabaseManager() {
return databaseManager;
}
public LuckPerms getLuckPerms() {
return luckPerms;
}
}
package com.adzel.velocitybroadcast;
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;
import com.velocitypowered.api.event.connection.LoginEvent;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.LuckPermsProvider;
@Plugin(
id = "velocitybroadcast",
name = "VelocityBroadcast",
version = "0.3.7",
description = "A proxy-wide broadcast plugin for Velocity.",
authors = {"Adzel"}
)
public class VelocityBroadcast {
public static final String PLUGIN_VERSION = "0.3.7";
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;
private LuckPerms luckPerms;
@Inject
public VelocityBroadcast(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
this.server = server;
this.logger = logger;
this.dataDirectory = dataDirectory;
}
@Subscribe(order = PostOrder.EARLY)
public void onProxyInitialization(ProxyInitializeEvent event) {
// Load config
this.config = new ConfigHandler(dataDirectory.resolve("config.yml"), logger);
config.load();
if (config.isDebugEnabled()) {
logger.info("[VelocityBroadcast] Debug mode is enabled.");
}
// Initialize LuckPerms
try {
this.luckPerms = LuckPermsProvider.get();
logger.info("[VelocityBroadcast] Successfully hooked into LuckPerms.");
} catch (IllegalStateException e) {
logger.error("[VelocityBroadcast] LuckPerms is not loaded! This plugin requires LuckPerms.");
return; // Prevent plugin from loading if LP is not available
}
// 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
server.getEventManager().register(this, new LoginListener(server, PLUGIN_VERSION, updateChecker, databaseManager));
// Register command
server.getCommandManager().register(
server.getCommandManager().metaBuilder("vb").plugin(this).build(),
new VBCommand(this)
);
logger.info("[VelocityBroadcast] Loaded VelocityBroadcast v" + PLUGIN_VERSION);
}
@Subscribe
public void onLogin(LoginEvent event) {
if (event.getPlayer().hasPermission("vb.admin") && config.isVersionCheckEnabled()) {
event.getPlayer().sendMessage(
MINI_MESSAGE.deserialize("<yellow>[VelocityBroadcast] You're running version " + PLUGIN_VERSION + ".</yellow>")
);
}
}
public ProxyServer getServer() {
return server;
}
public Logger getLogger() {
return logger;
}
public ConfigHandler getConfigHandler() {
return config;
}
public DatabaseManager getDatabaseManager() {
return databaseManager;
}
public LuckPerms getLuckPerms() {
return luckPerms;
}
}

View File

@@ -1,127 +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());
}
}
}
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());
}
}
}