From ad00f1e9936243ce102efac41456f46dd0f7dec4 Mon Sep 17 00:00:00 2001 From: Yanic Date: Sat, 24 Jan 2026 16:38:13 +0100 Subject: [PATCH 1/6] Reworked the code (#1) * Fix: Made the LocationWrapper extended LocationWrapperReduced to prevent duplicated code. * Fix: Added missing repository * Fix: Added the possibility to specify a max player value by a pattern and fixed a performance issue. * Fix: Re-added and improved the hashCode and equals methods for LocationWrapper * Fix: Refactored the toString method in LocationWrapperReduced and added a getter for defaultMaxPlayerCount. --------- Co-authored-by: yan13try <102859802+yan13try@users.noreply.github.com> --- pom.xml | 177 ++++++++++-------- .../codelib/locations/LocationWrapper.java | 81 ++------ .../locations/LocationWrapperReduced.java | 36 ++-- .../codelib/util/ServerConnector.java | 111 ++++++----- 4 files changed, 190 insertions(+), 215 deletions(-) diff --git a/pom.xml b/pom.xml index 3b88267..6fffc8e 100644 --- a/pom.xml +++ b/pom.xml @@ -2,19 +2,19 @@ - 4.0.0 + 4.0.0 - de.codeblocksmc.codelib - CodeLib - 3.6.4 - jar + de.codeblocksmc.codelib + CodeLib + 3.6.4 + jar - CodeLib + CodeLib - - 21 - UTF-8 - + + 21 + UTF-8 + @@ -23,79 +23,90 @@ - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.14.0 - - 21 - 21 - - - - org.apache.maven.plugins - maven-shade-plugin - 3.6.0 - - - package - - shade - - - - - - - - src/main/resources - true - - - + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + 21 + 21 + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + package + + shade + + + + + + + + src/main/resources + true + + + - - - papermc-repo - https://repo.papermc.io/repository/maven-public/ - - - sonatype - https://oss.sonatype.org/content/groups/public/ - - + - - - io.papermc.paper - paper-api - 1.21.6-R0.1-SNAPSHOT - provided - - - io.github.leonardosnt - bungeechannelapi - 1.0.0-SNAPSHOT - - - fr.mrmicky - fastboard - 2.1.5 - - - org.projectlombok - lombok - 1.18.42 - provided - - - - com.arcaniax - HeadDatabase-API - 1.3.2 - provided - - + + + codemc-repo + https://repo.codemc.org/repository/maven-public/ + + + + papermc-repo + https://repo.papermc.io/repository/maven-public/ + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + + + + + + + + io.papermc.paper + paper-api + 1.21.6-R0.1-SNAPSHOT + provided + + + io.github.leonardosnt + bungeechannelapi + 1.0.0-SNAPSHOT + + + fr.mrmicky + fastboard + 2.1.5 + + + org.projectlombok + lombok + 1.18.42 + provided + + + + com.arcaniax + HeadDatabase-API + 1.3.2 + provided + + \ No newline at end of file diff --git a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapper.java b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapper.java index d161785..46a905a 100644 --- a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapper.java +++ b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapper.java @@ -4,7 +4,10 @@ import lombok.Setter; import lombok.NoArgsConstructor; +import java.util.Objects; + /** + * @author Try * A wrapper class for representing and saving positions in JSON files. * *

This class is designed to store positional data in a safe and @@ -18,55 +21,16 @@ @Getter @Setter @NoArgsConstructor -public class LocationWrapper { +public class LocationWrapper extends LocationWrapperReduced { /** * The name of the world where the location exists. */ private String world; - /** - * The X-coordinate of the location. - */ - private double x; - - /** - * The Y-coordinate of the location. - */ - private double y; - - /** - * The Z-coordinate of the location. - */ - private double z; - - /** - * The yaw (rotation on the Y-axis) of the location. - */ - private float yaw; - - /** - * The pitch (rotation on the X-axis) of the location. - */ - private float pitch; - - /** - * Constructs a {@link LocationWrapper} with the specified values. - * - * @param world the name of the {@link org.bukkit.World} where the location exists. - * @param x the X-coordinate of the location. - * @param y the Y-coordinate of the location. - * @param z the Z-coordinate of the location. - * @param yaw the yaw (rotation on the Y-axis) of the location. - * @param pitch the pitch (rotation on the X-axis) of the location. - */ public LocationWrapper(String world, double x, double y, double z, float yaw, float pitch) { + super(x,y,z,yaw,pitch); this.world = world; - this.x = x; - this.y = y; - this.z = z; - this.yaw = yaw; - this.pitch = pitch; } /** @@ -80,6 +44,7 @@ public boolean isValid() { return world != null && !world.isEmpty(); } + /** * Provides a string representation of the {@link LocationWrapper}. * @@ -88,7 +53,7 @@ public boolean isValid() { @Override public String toString() { return String.format("LocationWrapper[world=%s, x=%.2f, y=%.2f, z=%.2f, yaw=%.2f, pitch=%.2f]", - world, x, y, z, yaw, pitch); + world, getX(), getY(), getZ(), getYaw(), getPitch()); } /** @@ -101,35 +66,17 @@ public String toString() { */ @Override public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; + boolean result = super.equals(obj); - LocationWrapper other = (LocationWrapper) obj; - return Double.compare(other.x, x) == 0 && - Double.compare(other.y, y) == 0 && - Double.compare(other.z, z) == 0 && - Float.compare(other.yaw, yaw) == 0 && - Float.compare(other.pitch, pitch) == 0 && - (world != null ? world.equals(other.world) : other.world == null); + if (obj instanceof LocationWrapper other) + return result&& (world != null ? world.equals(other.world) : other.world == null); + else{ + return false; + } } - /** - * Generates a hash code for the {@link LocationWrapper}. - * - * @return a hash code based on the fields of the object. - */ @Override public int hashCode() { - int result = (world != null ? world.hashCode() : 0); - long temp; - temp = Double.doubleToLongBits(x); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(y); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(z); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - result = 31 * result + Float.floatToIntBits(yaw); - result = 31 * result + Float.floatToIntBits(pitch); - return result; + return Objects.hash(super.hashCode(), world); } } diff --git a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java index 25a49a2..dd50aaa 100644 --- a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java +++ b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java @@ -4,7 +4,10 @@ import lombok.NoArgsConstructor; import lombok.Setter; +import java.util.Objects; + /** + * @author Try * A wrapper class for representing and saving positions in JSON files. * *

This class is designed to store positional data in a safe and @@ -84,8 +87,8 @@ public LocationWrapper toWrapper(String world) { */ @Override public String toString() { - return String.format("LocationWrapper[world=%s, x=%.2f, y=%.2f, z=%.2f, yaw=%.2f, pitch=%.2f]", - "unknown", x, y, z, yaw, pitch); + return String.format("LocationWrapperReduced[ x=%.2f, y=%.2f, z=%.2f, yaw=%.2f, pitch=%.2f]", + x, y, z, yaw, pitch); } /** @@ -98,15 +101,19 @@ public String toString() { */ @Override public boolean equals(Object obj) { + if (obj == null ) return false; if (this == obj) return true; - if (obj == null || getClass() != obj.getClass()) return false; - - LocationWrapperReduced other = (LocationWrapperReduced) obj; - return Double.compare(other.x, x) == 0 && - Double.compare(other.y, y) == 0 && - Double.compare(other.z, z) == 0 && - Float.compare(other.yaw, yaw) == 0 && - Float.compare(other.pitch, pitch) == 0; + + if(obj instanceof LocationWrapperReduced other){ + return Double.compare(other.x, x) == 0 && + Double.compare(other.y, y) == 0 && + Double.compare(other.z, z) == 0 && + Float.compare(other.yaw, yaw) == 0 && + Float.compare(other.pitch, pitch) == 0; + } + + return false; + } /** @@ -114,14 +121,9 @@ public boolean equals(Object obj) { * * @return a hash code based on the fields of the object. */ + @Override public int hashCode() { - int result = 0; - result = 31 * result + Double.hashCode(x); - result = 31 * result + Double.hashCode(y); - result = 31 * result + Double.hashCode(z); - result = 31 * result + Float.floatToIntBits(yaw); - result = 31 * result + Float.floatToIntBits(pitch); - return result; + return Objects.hash(x, y, z, yaw, pitch); } } diff --git a/src/main/java/de/codeblocksmc/codelib/util/ServerConnector.java b/src/main/java/de/codeblocksmc/codelib/util/ServerConnector.java index 6d4ea1a..86d6a0e 100644 --- a/src/main/java/de/codeblocksmc/codelib/util/ServerConnector.java +++ b/src/main/java/de/codeblocksmc/codelib/util/ServerConnector.java @@ -1,11 +1,15 @@ package de.codeblocksmc.codelib.util; import io.github.leonardosnt.bungeechannelapi.BungeeChannelApi; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.scheduler.BukkitRunnable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Pattern; /** * This class handles the connection of players to available servers, taking into account party-related restrictions. @@ -18,9 +22,15 @@ * This class operates asynchronously, querying the BungeeCord server list and checking for server availability. * * @author JustCody - * @version 1.0 + * @author Try + * @version 1.1 */ public class ServerConnector { + private final ConcurrentHashMap serverMaxPlayerCount = new ConcurrentHashMap<>(); + + @Setter + @Getter + private int defaultMaxPlayerCount = 30; // Prefix that is used for messages sent to players private final String prefix; @@ -56,59 +66,64 @@ protected ServerConnector(JavaPlugin plugin, String prefix) { *

* The method will search for a server that is less than 30 players, and if found, it will connect the player to it. * - * @param player The player to be connected. - * @param servername The name of the server to connect to (partial match). + * @param player The player to be connected. + * @param serverPattern A pattern to match server names. + * @param searchDescription The description which is show to the player when the searching is starting. */ - public void connect(Player player, String servername) { - // Check if the player is in a party and not the leader - //TODO: Use new party system + public void connect(Player player, Pattern serverPattern, String searchDescription) { + + //If the pattern is not known register it with the default player count. + if (!serverMaxPlayerCount.containsKey(serverPattern)) + serverMaxPlayerCount.put(serverPattern, defaultMaxPlayerCount); + - // Notify the player that the search for a free server is starting - player.sendMessage(prefix + "§aLooking for free server in §e" + servername + "§a..."); + player.sendMessage(prefix + "§aLooking for free server in §e" + searchDescription + "§a..."); - // Get the BungeeChannelApi instance to interact with BungeeCord BungeeChannelApi api = BungeeChannelApi.of(plugin); - // Run the connection task asynchronously - new BukkitRunnable() { - - @Override - public void run() { - // Fetch the list of available servers - api.getServers().whenComplete((result, error) -> { - AtomicBoolean found = new AtomicBoolean(false); - - // Loop through the servers and check if one matches the specified servername - for (String server : result) { - if (!server.startsWith(servername)) continue; - - // Get the player count for the current server - api.getPlayerCount(server).whenComplete((count, err) -> { - // If the server has less than 30 players, connect the player - if (count < 30) { - api.connect(player, server); - found.set(true); - } - }); - } + Bukkit.getScheduler().runTaskLater(plugin, () -> { + api.getServers().whenComplete((result, error) -> { + AtomicBoolean found = new AtomicBoolean(false); + - // Notify the player if no free server was found after the search - new BukkitRunnable() { - @Override - public void run() { - try { - if (!found.get()) { - player.sendMessage(prefix + "§7We could not find a free server. Sorry for the inconvenience!"); - } - } catch (Exception e) { - // Handle any errors when notifying the player - plugin.getLogger().warning(e.getMessage()); - } + for (String server : result) { + if (!serverPattern.matcher(server).hasMatch()) continue; + + + + api.getPlayerCount(server).whenComplete((count, err) -> { + + if (count < serverMaxPlayerCount.get(serverPattern)) { + api.connect(player, server); + found.set(true); } - }.runTaskLater(plugin, 5); // Delay to allow for the server search to complete - }); - } + }); + + //stop the search if a server is found + if(found.get()) + break; + } + + //There is no reason to start a task if the server is found. + if (found.get()) return; + + Bukkit.getScheduler().runTaskLater(plugin, () -> { + + try { + player.sendMessage(prefix + "§7We could not find a free server. Sorry for the inconvenience!"); + } catch (Exception e) { + plugin.getLogger().warning(e.getMessage()); + } + + }, 5); + }); + + }, 0); + + } + - }.runTaskLater(plugin, 0); // Run the task immediately + public void setServerMaxPlayerCount(Pattern serverPattern, int playerCount) { + this.serverMaxPlayerCount.put(serverPattern, playerCount); } } From 775bbac8b151312446aa6dbe4fceffc87b2434a4 Mon Sep 17 00:00:00 2001 From: Philipp <62473021+CrAfTsArMy@users.noreply.github.com> Date: Sat, 24 Jan 2026 16:47:21 +0100 Subject: [PATCH 2/6] fix: Optimize sql templates (#2) * SQLTemplate now has a purpose * Massively duplicated code removed * No more silent catch and log exceptions * No more logging within the lib code --- .../codelib/databsae/DatabaseObject.java | 4 - .../codelib/databsae/MSSQLTemplate.java | 120 ++++++++----- .../codelib/databsae/MySQLTemplate.java | 134 +++++++-------- .../databsae/MySQLTemplateVelocity.java | 73 -------- .../codelib/databsae/SQLTemplate.java | 161 ++++++++++++++++++ 5 files changed, 298 insertions(+), 194 deletions(-) delete mode 100644 src/main/java/de/codeblocksmc/codelib/databsae/DatabaseObject.java delete mode 100644 src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplateVelocity.java create mode 100644 src/main/java/de/codeblocksmc/codelib/databsae/SQLTemplate.java diff --git a/src/main/java/de/codeblocksmc/codelib/databsae/DatabaseObject.java b/src/main/java/de/codeblocksmc/codelib/databsae/DatabaseObject.java deleted file mode 100644 index eb40cc9..0000000 --- a/src/main/java/de/codeblocksmc/codelib/databsae/DatabaseObject.java +++ /dev/null @@ -1,4 +0,0 @@ -package de.codeblocksmc.codelib.databsae; - -public class DatabaseObject { -} diff --git a/src/main/java/de/codeblocksmc/codelib/databsae/MSSQLTemplate.java b/src/main/java/de/codeblocksmc/codelib/databsae/MSSQLTemplate.java index cc7b197..2d6018f 100644 --- a/src/main/java/de/codeblocksmc/codelib/databsae/MSSQLTemplate.java +++ b/src/main/java/de/codeblocksmc/codelib/databsae/MSSQLTemplate.java @@ -2,57 +2,87 @@ import lombok.Getter; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.logging.Logger; +/** + * Abstract Microsoft SQL Server specific implementation of {@link SQLTemplate}. + * + * @author JustCody + * @author CrAfTs_ArMy + * @version 2.0 + */ +public abstract non-sealed class MSSQLTemplate extends SQLTemplate { -public class MSSQLTemplate extends DatabaseObject { + /** + * Additional JDBC connection flags appended to the connection URL. + */ @Getter - public Connection conn; - private final Logger log; - private final String DB_NAME; - private final String DB_USER; - private final String DB_PASSWORD; - private final int DB_PORT; - private final String DB_HOST; - - public MSSQLTemplate(Logger log, String DB_NAME, String DB_USER, String DB_PASSWORD, int DB_PORT, String DB_HOST) { - this.log = log; - this.DB_NAME = DB_NAME; - this.DB_USER = DB_USER; - this.DB_PASSWORD = DB_PASSWORD; - this.DB_PORT = DB_PORT; - this.DB_HOST = DB_HOST; + private final String additionalFlags; + + /** + * Creates a new MSSQLTemplate without any additional connection flags. + * + * @param host The database host + * @param port The database port + * @param database The database name + * @param user The database user + * @param password The database password + */ + public MSSQLTemplate(String host, int port, String database, String user, String password) { + super(host, port, database, user, password); + this.additionalFlags = ""; } - public Connection connect() { - String CONNECTION_STRING = "jdbc:sqlserver://HOST;databaseName=DATABASE;encrypt=false;trustServerCertificate=true;" - .replace("HOST", DB_HOST).replace("DATABASE", DB_NAME); - try { - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - conn = DriverManager.getConnection(CONNECTION_STRING, DB_USER, DB_PASSWORD); - log.info("MSSQL Connection established."); - conn.createStatement().execute("USE " + DB_NAME); - return conn; - } - catch(Exception ex) { - log.warning(ex.getMessage()); - } - return null; + /** + * Creates a new MSSQLTemplate with additional JDBC connection flags. + *

+ * Each flag should be provided in the format {@code key=value}. + * Multiple flags will be joined using {@code ;}. + *

+ * + * @param host The database host + * @param port The database port + * @param database The database name + * @param user The database user + * @param password The database password + * @param additionalFlags Optional JDBC connection flags + */ + public MSSQLTemplate(String host, int port, String database, String user, String password, String... additionalFlags) { + super(host, port, database, user, password); + this.additionalFlags = String.join(";", additionalFlags); } - public void checkConnection() { - try { - if (conn == null || conn.isClosed()) connect(); - } catch (SQLException ignored) {} + /** + * Returns the fully qualified Microsoft SQL Server JDBC driver class name. + * + * @return The SQL Server JDBC driver class + */ + @Override + protected String getDriverClass() { + return "com.microsoft.sqlserver.jdbc.SQLServerDriver"; } - public void disconnect() { - try { - conn.close(); - log.info("SQL Connection destroyed."); - } catch (SQLException e) { - log.severe(e.getMessage()); - } + + /** + * Builds the Microsoft SQL Server JDBC connection URL. + *

+ * The URL follows the format: + * {@code jdbc:sqlserver://host:port;databaseName=database} + * and optionally appends additional connection properties. + *

+ * + * @return The JDBC connection URL template + */ + @Override + protected String getConnectionUrl() { + String url = "jdbc:sqlserver://%host%:%port%;databaseName=%database%"; + return url + (hasAdditionalFlags() ? ";" + additionalFlags : ""); } + + /** + * Checks whether any additional JDBC connection flags are defined. + * + * @return {@code true} if additional flags are present, otherwise {@code false} + */ + public boolean hasAdditionalFlags() { + return additionalFlags != null && !additionalFlags.isBlank(); + } + } diff --git a/src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplate.java b/src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplate.java index 0596f8d..ca265b7 100644 --- a/src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplate.java +++ b/src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplate.java @@ -1,98 +1,88 @@ package de.codeblocksmc.codelib.databsae; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.logging.Logger; +import lombok.Getter; /** - * Template class for creating MySQL connections. - * This class provides methods for connecting to a MySQL database and checking the connection status. - * It works in conjunction with {@link Logger} for logging any issues or errors during the connection process. - * This is commonly used in Bukkit and Paper plugins for logging database-related activities. + * Abstract MySQL-specific implementation of {@link SQLTemplate}. * * @author JustCody - * @version 1.0 + * @author CrAfTs_ArMy + * @version 2.0 */ -public abstract class MySQLTemplate extends DatabaseObject { +public abstract non-sealed class MySQLTemplate extends SQLTemplate { - // The connection object to the MySQL database - public Connection conn; - - // Logger for logging messages related to the connection - public final Logger log; - - // MySQL connection details - public final String host; - public final int port; - public final String database; - public final String user; - public final String password; + /** + * Additional JDBC connection flags appended to the connection URL. + */ + @Getter + private final String additionalFlags; /** - * Constructor for initializing the MySQL connection template. + * Creates a new MySQLTemplate without any additional connection flags. * - * @param log {@link Logger} of the plugin, typically used to log connection issues. - * @param host Hostname of the MySQL server (e.g., "localhost"). - * @param port Port of the MySQL server. Default is 3306. - * @param database Name of the MySQL database to connect to. - * @param user Username to authenticate with the MySQL server. - * @param password Password for the given username. + * @param host The database host + * @param port The database port + * @param database The database name + * @param user The database user + * @param password The database password */ - public MySQLTemplate(Logger log, String host, int port, String database, String user, String password) { - this.log = log; - this.host = host; - this.port = port; - this.database = database; - this.user = user; - this.password = password; + public MySQLTemplate(String host, int port, String database, String user, String password) { + super(host, port, database, user, password); + this.additionalFlags = ""; } /** - * Establishes a connection to the MySQL server and creates a {@link Connection} object. - * This method loads the MySQL JDBC driver, attempts to connect to the database, - * and logs any exceptions if the connection fails. + * Creates a new MySQLTemplate with additional JDBC connection flags. + *

+ * Each flag should be provided in the format {@code key=value}. + * Multiple flags will be joined using {@code &}. + *

+ * + * @param host The database host + * @param port The database port + * @param database The database name + * @param user The database user + * @param password The database password + * @param additionalFlags Optional JDBC connection flags */ - public void connect() { - final String DB_NAME = "jdbc:mysql://"+host+":"+port+"/"+database+"?useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC&autoReconnect=true"; - - try { - // Load MySQL JDBC driver class - Class.forName("com.mysql.cj.jdbc.Driver"); - - // Establish a connection using the provided connection details - conn = DriverManager.getConnection(DB_NAME, user, password); + public MySQLTemplate(String host, int port, String database, String user, String password, String... additionalFlags) { + super(host, port, database, user, password); + this.additionalFlags = String.join("&", additionalFlags); + } - afterSuccessfulConnection(); - } catch (Exception ex) { - // Log any exception that occurs during the connection process - log.warning("MySQL connection failed: " + ex.getMessage()); - } + /** + * Returns the fully qualified MySQL JDBC driver class name. + * + * @return The MySQL JDBC driver class + */ + @Override + protected String getDriverClass() { + return "com.mysql.cj.jdbc.Driver"; } /** - * Checks the current MySQL connection to verify if it is still open and valid. - * If the connection is closed or null, this method will attempt to reconnect using {@link MySQLTemplate#connect()}. + * Builds the MySQL JDBC connection URL. + *

+ * The URL follows the format: + * {@code jdbc:mysql://host:port/database} + * and optionally appends query parameters if additional flags are present. + *

+ * + * @return The JDBC connection URL template */ - public void checkConnection() { - try { - if (conn == null || conn.isClosed()) { - // Attempt to reconnect if the connection is null or closed - connect(); - } - } catch (SQLException e) { - // Log any exceptions encountered while checking the connection status - log.warning("MySQL connection check failed: " + e.getMessage()); - } + @Override + protected String getConnectionUrl() { + String url = "jdbc:mysql://%host%:%port%/%database%"; + return url + (hasAdditionalFlags() ? "?" + additionalFlags : ""); } - public void disconnect() { - try { - conn.close(); - } catch (SQLException e) { - log.severe(e.getMessage()); - } + /** + * Checks whether any additional JDBC connection flags are defined. + * + * @return {@code true} if additional flags are present, otherwise {@code false} + */ + public boolean hasAdditionalFlags() { + return additionalFlags != null && !additionalFlags.isBlank(); } - public abstract void afterSuccessfulConnection(); } diff --git a/src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplateVelocity.java b/src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplateVelocity.java deleted file mode 100644 index 0f33d84..0000000 --- a/src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplateVelocity.java +++ /dev/null @@ -1,73 +0,0 @@ -package de.codeblocksmc.codelib.databsae; - -import org.slf4j.Logger; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; - - -/** - * Template class for creating MySQL connections - */ -public abstract class MySQLTemplateVelocity extends DatabaseObject { - - public Connection conn; - public final Logger log; - - private final String host; - private final int port; - private final String database; - private final String user; - private final String password; - - /** - * - * @param log {@link Logger} of the Plugin - * @param host Hostname - * @param port Port of the server. Default: 3306 - * @param database Database name - * @param user Username - * @param password Password - */ - public MySQLTemplateVelocity(Logger log, String host, int port, String database, String user, String password) { - this.log = log; - this.host = host; - this.port = port; - this.database = database; - this.user = user; - this.password = password; - } - - /** - * Connects to the MySQL server and creates a {@link Connection} object - */ - public void connect() { - final String DB_NAME = "jdbc:mysql://"+host+":"+port+"/"+database+"?useJDBCCompliantTimezoneShift=true&useLeg" + - "acyDatetimeCode=false&serverTimezone=UTC&autoReconnect=true"; - - try { - Class.forName("com.mysql.cj.jdbc.Driver"); //Gets the driver class - - conn = DriverManager.getConnection(DB_NAME, user, password); //Gets a connection to the database using the details you provided. - afterSuccessfulConnection(); - - } - catch(Exception ex) { - log.warn(ex.getMessage()); - } - } - - /** - * Checks if the connection is ok, otherwise it will try to {@link MySQLTemplate#connect()} to the server - */ - public void checkConnection() { - try { - if (conn == null || conn.isClosed()) connect(); - } catch (SQLException e) { - log.warn(e.getMessage()); - } - } - - public abstract void afterSuccessfulConnection(); -} diff --git a/src/main/java/de/codeblocksmc/codelib/databsae/SQLTemplate.java b/src/main/java/de/codeblocksmc/codelib/databsae/SQLTemplate.java new file mode 100644 index 0000000..c5d2b28 --- /dev/null +++ b/src/main/java/de/codeblocksmc/codelib/databsae/SQLTemplate.java @@ -0,0 +1,161 @@ +package de.codeblocksmc.codelib.databsae; + +import lombok.Getter; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * Abstract base class for SQL database templates. + * + * @author CrAfTs_ArMy + * @version 1.0 + */ +public sealed abstract class SQLTemplate permits MSSQLTemplate, MySQLTemplate { + + /** + * The database host address. + */ + private final String host; + + /** + * The port on which the database server is running. + */ + private final int port; + + /** + * The name of the database schema to connect to. + */ + private final String database; + + /** + * The username used for database authentication. + */ + private final String user; + + /** + * The password used for database authentication. + */ + private final String password; + + /** + * The active JDBC connection. + */ + @Getter + private Connection connection; + + /** + * Creates a new {@link SQLTemplate} with the given connection parameters. + * + * @param host The database host + * @param port The database port + * @param database The database name + * @param user The database user + * @param password The database password + */ + public SQLTemplate(String host, int port, String database, String user, String password) { + this.host = host; + this.port = port; + this.database = database; + this.user = user; + this.password = password; + } + + /** + * Hook method that is called after a successful database connection. + */ + protected abstract void afterSuccessfulConnection(); + + /** + * Returns the JDBC connection URL template. + *

+ * The returned string may contain the placeholders: + *

+ * which will be replaced before establishing the connection. + *

+ * + * @return The JDBC connection URL template + */ + protected abstract String getConnectionUrl(); + + /** + * Returns the fully qualified class name of the JDBC driver. + *

+ * If {@code null} is returned, no explicit driver loading will be attempted. + *

+ * + * @return The JDBC driver class name or {@code null} + */ + protected abstract String getDriverClass(); + + /** + * Establishes a connection to the database. + *

+ * This method loads the JDBC driver (if provided), builds the connection URL, + * and opens a connection using {@link DriverManager}. + *

+ * + * @return The established {@link Connection} + * @throws RuntimeException If the driver cannot be loaded or the connection fails + */ + public Connection connect() { + try { + String driverClass = getDriverClass(); + if (driverClass != null) { + Class.forName(driverClass); + } + + String connectionUrl = getConnectionUrl() + .replace("%host%", host) + .replace("%port%", String.valueOf(port)) + .replace("%database%", database); + + connection = DriverManager.getConnection(connectionUrl, user, password); + afterSuccessfulConnection(); + return connection; + } catch (ClassNotFoundException e) { + throw new RuntimeException("Failed to load driver: " + e.getMessage()); + } catch (SQLException e) { + throw new RuntimeException("Failed to connect: " + e.getMessage(), e); + } + } + + /** + * Closes the current database connection. + * + * @throws RuntimeException if closing the connection fails + */ + public void disconnect() { + try { + getConnection().close(); + } catch (SQLException e) { + throw new RuntimeException("Failed to disconnect: " + e.getMessage(), e); + } + } + + /** + * Checks whether the database connection is active. + *

+ * If the connection is {@code null} or already closed, + * a new connection will be established automatically. + *

+ * + * @throws RuntimeException if checking the connection fails + */ + public void checkConnection() { + try { + Connection connection = getConnection(); + if (connection == null || connection.isClosed()) { + this.connect(); + } + } catch (SQLException e) { + throw new RuntimeException("Failed to check the connection: " + e.getMessage(), e); + } + } + +} From a37749e593cffbf19f90e3ee216a42d55d3b558e Mon Sep 17 00:00:00 2001 From: Philipp <62473021+CrAfTsArMy@users.noreply.github.com> Date: Sat, 24 Jan 2026 16:48:38 +0100 Subject: [PATCH 3/6] chore: Small adjustments --- .../java/de/codeblocksmc/codelib/locations/LocationWrapper.java | 2 +- .../codeblocksmc/codelib/locations/LocationWrapperReduced.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapper.java b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapper.java index 46a905a..32f093a 100644 --- a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapper.java +++ b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapper.java @@ -69,7 +69,7 @@ public boolean equals(Object obj) { boolean result = super.equals(obj); if (obj instanceof LocationWrapper other) - return result&& (world != null ? world.equals(other.world) : other.world == null); + return result&& (Objects.equals(world, other.world)); else{ return false; } diff --git a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java index dd50aaa..9f30cf0 100644 --- a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java +++ b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java @@ -121,7 +121,6 @@ public boolean equals(Object obj) { * * @return a hash code based on the fields of the object. */ - @Override public int hashCode() { return Objects.hash(x, y, z, yaw, pitch); From 077ea95d0e2df1136c7375610870b5842297cd9f Mon Sep 17 00:00:00 2001 From: Yanic Date: Sat, 24 Jan 2026 16:50:57 +0100 Subject: [PATCH 4/6] Reworked the spawnRotatingCircle to use the Bukkit Scheduler. (#3) * Fix: Made the LocationWrapper extended LocationWrapperReduced to prevent duplicated code. * Fix: Added missing repository * Fix: Added the possibility to specify a max player value by a pattern and fixed a performance issue. * Fix: Re-added and improved the hashCode and equals methods for LocationWrapper * Fix: Refactored the toString method in LocationWrapperReduced and added a getter for defaultMaxPlayerCount. * Fix: Reworked the spawnRotatingCircle to use the Bukkit Scheduler. --------- Co-authored-by: yan13try <102859802+yan13try@users.noreply.github.com> Co-authored-by: Philipp <62473021+CrAfTsArMy@users.noreply.github.com> --- .../locations/LocationWrapperReduced.java | 1 + .../codelib/util/ParticleUtil.java | 42 ++++++++++--------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java index 9f30cf0..dd50aaa 100644 --- a/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java +++ b/src/main/java/de/codeblocksmc/codelib/locations/LocationWrapperReduced.java @@ -121,6 +121,7 @@ public boolean equals(Object obj) { * * @return a hash code based on the fields of the object. */ + @Override public int hashCode() { return Objects.hash(x, y, z, yaw, pitch); diff --git a/src/main/java/de/codeblocksmc/codelib/util/ParticleUtil.java b/src/main/java/de/codeblocksmc/codelib/util/ParticleUtil.java index e01ed6f..0b5b161 100644 --- a/src/main/java/de/codeblocksmc/codelib/util/ParticleUtil.java +++ b/src/main/java/de/codeblocksmc/codelib/util/ParticleUtil.java @@ -1,12 +1,20 @@ package de.codeblocksmc.codelib.util; +import com.google.common.util.concurrent.AtomicDouble; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; import org.bukkit.util.Vector; +/* + * @author Try + * @version 1.1 + */ + public class ParticleUtil { public static void spawnParticleCircle(Location center, double radius, Particle particle, int points) { World world = center.getWorld(); @@ -25,29 +33,25 @@ public static void spawnRotatingCircle(Location center, double radius, Particle World world = center.getWorld(); if (world == null) return; - new BukkitRunnable() { - int ticks = 0; - double angleOffset = 0; - @Override - public void run() { - if (ticks >= durationTicks) { - cancel(); - return; - } - for (int i = 0; i < points; i++) { - double angle = 2 * Math.PI * i / points + angleOffset; - double x = Math.cos(angle) * radius; - double z = Math.sin(angle) * radius; - Location loc = center.clone().add(new Vector(x, 0, z)); - world.spawnParticle(particle, loc, 1, 0, 0, 0, 0); - } - angleOffset += angularVelocity; - ticks += 2; + final AtomicDouble angleOffset = new AtomicDouble(0); + + BukkitTask particleTask = Bukkit.getScheduler().runTaskTimer(plugin,()->{ + + for (int i = 0; i < points; i++) { + double angle = 2 * Math.PI * i / points + angleOffset.get(); + double x = Math.cos(angle) * radius; + double z = Math.sin(angle) * radius; + Location loc = center.clone().add(new Vector(x, 0, z)); + world.spawnParticle(particle, loc, 1, 0, 0, 0, 0); } - }.runTaskTimer(plugin, 0, 2L); + angleOffset.addAndGet(angularVelocity); + + }, 0, 2L); + + Bukkit.getScheduler().runTaskLater(plugin, particleTask::cancel, durationTicks); } From 44d26f9d63f039b34d54623b88544728882cd720 Mon Sep 17 00:00:00 2001 From: Philipp <62473021+CrAfTsArMy@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:03:30 +0100 Subject: [PATCH 5/6] feat: Add try and me to the readme :stonks: --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 913dc72..b6ba100 100644 --- a/README.md +++ b/README.md @@ -74,3 +74,5 @@ This project is licensed under the [GNU GPL v3 License](https://www.gnu.org/lice @PhastixTV @zCreeperYT @ProJakob +@liyanic +@CrAfTsArMy From 5d850137c2cf8c5b2488a2d14ca31c475fc4fccd Mon Sep 17 00:00:00 2001 From: Philipp <62473021+CrAfTsArMy@users.noreply.github.com> Date: Sat, 24 Jan 2026 17:06:05 +0100 Subject: [PATCH 6/6] fix: Fix a typo in the package name --- .../codelib/{databsae => database}/MSSQLTemplate.java | 2 +- .../codelib/{databsae => database}/MySQLTemplate.java | 2 +- .../codelib/{databsae => database}/SQLTemplate.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/main/java/de/codeblocksmc/codelib/{databsae => database}/MSSQLTemplate.java (98%) rename src/main/java/de/codeblocksmc/codelib/{databsae => database}/MySQLTemplate.java (98%) rename src/main/java/de/codeblocksmc/codelib/{databsae => database}/SQLTemplate.java (99%) diff --git a/src/main/java/de/codeblocksmc/codelib/databsae/MSSQLTemplate.java b/src/main/java/de/codeblocksmc/codelib/database/MSSQLTemplate.java similarity index 98% rename from src/main/java/de/codeblocksmc/codelib/databsae/MSSQLTemplate.java rename to src/main/java/de/codeblocksmc/codelib/database/MSSQLTemplate.java index 2d6018f..4b7f603 100644 --- a/src/main/java/de/codeblocksmc/codelib/databsae/MSSQLTemplate.java +++ b/src/main/java/de/codeblocksmc/codelib/database/MSSQLTemplate.java @@ -1,4 +1,4 @@ -package de.codeblocksmc.codelib.databsae; +package de.codeblocksmc.codelib.database; import lombok.Getter; diff --git a/src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplate.java b/src/main/java/de/codeblocksmc/codelib/database/MySQLTemplate.java similarity index 98% rename from src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplate.java rename to src/main/java/de/codeblocksmc/codelib/database/MySQLTemplate.java index ca265b7..149e210 100644 --- a/src/main/java/de/codeblocksmc/codelib/databsae/MySQLTemplate.java +++ b/src/main/java/de/codeblocksmc/codelib/database/MySQLTemplate.java @@ -1,4 +1,4 @@ -package de.codeblocksmc.codelib.databsae; +package de.codeblocksmc.codelib.database; import lombok.Getter; diff --git a/src/main/java/de/codeblocksmc/codelib/databsae/SQLTemplate.java b/src/main/java/de/codeblocksmc/codelib/database/SQLTemplate.java similarity index 99% rename from src/main/java/de/codeblocksmc/codelib/databsae/SQLTemplate.java rename to src/main/java/de/codeblocksmc/codelib/database/SQLTemplate.java index c5d2b28..58bf9b4 100644 --- a/src/main/java/de/codeblocksmc/codelib/databsae/SQLTemplate.java +++ b/src/main/java/de/codeblocksmc/codelib/database/SQLTemplate.java @@ -1,4 +1,4 @@ -package de.codeblocksmc.codelib.databsae; +package de.codeblocksmc.codelib.database; import lombok.Getter;