From e567f9f58f1b2d792b198a7d5425266036565d7e Mon Sep 17 00:00:00 2001 From: AxenoDev Date: Sat, 7 Feb 2026 14:53:27 +0100 Subject: [PATCH 1/9] update: add HomeListMenu for improved home management and integrate menu-lib --- build.gradle | 6 +- gradle.properties | 2 + src/main/java/me/axeno/hommr/Hommr.java | 3 + .../me/axeno/hommr/commands/HomeCommands.java | 37 ++-- .../me/axeno/hommr/menus/HomeListMenu.java | 164 ++++++++++++++++++ 5 files changed, 194 insertions(+), 18 deletions(-) create mode 100644 src/main/java/me/axeno/hommr/menus/HomeListMenu.java diff --git a/build.gradle b/build.gradle index 488181b..eb8b152 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,5 @@ + import org.gradle.api.tasks.testing.logging.TestExceptionFormat + plugins { id 'java' id 'maven-publish' @@ -46,6 +48,8 @@ dependencies { implementation("org.xerial:sqlite-jdbc:${sqlite_jdbc_version}") implementation("com.mysql:mysql-connector-j:${mysql_connector_version}") + implementation("com.github.Xernas78:menu-lib:${menulib_version}") + compileOnly("org.projectlombok:lombok:${lombok_version}") annotationProcessor("org.projectlombok:lombok:${lombok_version}") @@ -75,7 +79,7 @@ tasks { useJUnitPlatform() testLogging { events("passed", "skipped", "failed") - exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL + exceptionFormat = TestExceptionFormat.FULL showStandardStreams = false } } diff --git a/gradle.properties b/gradle.properties index 0682288..55a2d56 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,6 +5,8 @@ lombok_version=1.18.38 revxrsal_lamp_version=4.0.0-rc.14 revxrsal_paper_version=4.0.0-beta.19 +menulib_version=1.3.6 + ormlite_version=6.1 sqlite_jdbc_version=3.51.1.0 mysql_connector_version=9.6.0 diff --git a/src/main/java/me/axeno/hommr/Hommr.java b/src/main/java/me/axeno/hommr/Hommr.java index 18b6345..74fccb4 100644 --- a/src/main/java/me/axeno/hommr/Hommr.java +++ b/src/main/java/me/axeno/hommr/Hommr.java @@ -1,5 +1,6 @@ package me.axeno.hommr; +import dev.xernas.menulib.MenuLib; import lombok.Getter; import me.axeno.hommr.api.HommrApi; import me.axeno.hommr.api.impl.HommrApiImpl; @@ -37,6 +38,8 @@ public void onEnable() { HomeManager.init(); + MenuLib.init(this); + this.api = new HommrApiImpl(); Bukkit.getServicesManager().register(HommrApi.class, api, this, ServicePriority.Normal); diff --git a/src/main/java/me/axeno/hommr/commands/HomeCommands.java b/src/main/java/me/axeno/hommr/commands/HomeCommands.java index 9e362ec..eacd630 100644 --- a/src/main/java/me/axeno/hommr/commands/HomeCommands.java +++ b/src/main/java/me/axeno/hommr/commands/HomeCommands.java @@ -1,6 +1,7 @@ package me.axeno.hommr.commands; import me.axeno.hommr.managers.HomeManager; +import me.axeno.hommr.menus.HomeListMenu; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -31,23 +32,25 @@ public void noArgs(Player player) { return; } - msg(player, Component.text("Your Homes", NamedTextColor.GOLD, TextDecoration.BOLD)); - - for (String homeName : homes) { - HomeManager.getHome(player.getUniqueId(), homeName).ifPresent(home -> { - String worldInfo = home.getWorld(); - player.sendMessage(Component.text() - .append(Component.text(" • ", NamedTextColor.DARK_GRAY)) - .append(Component.text(homeName, NamedTextColor.YELLOW)) - .append(Component.text(" (" + worldInfo + ")", NamedTextColor.GRAY)) - .build()); - }); - } - - player.sendMessage(Component.text() - .append(Component.text(" Total: ", NamedTextColor.GOLD)) - .append(Component.text(homes.size() + " home(s)", NamedTextColor.YELLOW)) - .build()); + new HomeListMenu(player).open(); + +// msg(player, Component.text("Your Homes", NamedTextColor.GOLD, TextDecoration.BOLD)); +// +// for (String homeName : homes) { +// HomeManager.getHome(player.getUniqueId(), homeName).ifPresent(home -> { +// String worldInfo = home.getWorld(); +// player.sendMessage(Component.text() +// .append(Component.text(" • ", NamedTextColor.DARK_GRAY)) +// .append(Component.text(homeName, NamedTextColor.YELLOW)) +// .append(Component.text(" (" + worldInfo + ")", NamedTextColor.GRAY)) +// .build()); +// }); +// } +// +// player.sendMessage(Component.text() +// .append(Component.text(" Total: ", NamedTextColor.GOLD)) +// .append(Component.text(homes.size() + " home(s)", NamedTextColor.YELLOW)) +// .build()); } @Command("home ") diff --git a/src/main/java/me/axeno/hommr/menus/HomeListMenu.java b/src/main/java/me/axeno/hommr/menus/HomeListMenu.java new file mode 100644 index 0000000..7560ca6 --- /dev/null +++ b/src/main/java/me/axeno/hommr/menus/HomeListMenu.java @@ -0,0 +1,164 @@ +package me.axeno.hommr.menus; + +import dev.xernas.menulib.PaginatedMenu; +import dev.xernas.menulib.utils.InventorySize; +import dev.xernas.menulib.utils.ItemBuilder; +import me.axeno.hommr.managers.HomeManager; +import me.axeno.hommr.models.Home; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +public class HomeListMenu extends PaginatedMenu { + + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm"); + private final List homes; + + public HomeListMenu(Player owner) { + super(owner); + // Récupérer tous les homes du joueur + Set homeNames = HomeManager.getHomeNames(owner.getUniqueId()); + this.homes = homeNames.stream() + .map(name -> HomeManager.getHome(owner.getUniqueId(), name)) + .filter(Optional::isPresent) + .map(Optional::get) + .sorted(Comparator.comparing(Home::getName)) + .collect(Collectors.toList()); + } + + @Override + public @Nullable Material getBorderMaterial() { + return Material.GRAY_STAINED_GLASS_PANE; + } + + @Override + public @NotNull List getStaticSlots() { + return List.of(49); // Slot pour le bouton de fermeture + } + + @Override + public List getItems() { + List items = new ArrayList<>(); + for (Home home : homes) { + List lore = new ArrayList<>(); + lore.add("§7Monde: §f" + home.getWorld()); + lore.add("§7X: §f" + String.format("%.2f", home.getX())); + lore.add("§7Y: §f" + String.format("%.2f", home.getY())); + lore.add("§7Z: §f" + String.format("%.2f", home.getZ())); + lore.add("§7Créé le: §f" + DATE_FORMAT.format(new Date(home.getCreatedAt()))); + lore.add(""); + lore.add("§aCliquez pour vous téléporter"); + lore.add("§cShift + Clic pour supprimer"); + + ItemStack item = new ItemBuilder(this, Material.RED_BED, it -> { + it.setDisplayName("§e" + home.getName()); + it.setLore(lore); + }); + + items.add(item); + } + return items; + } + + @Override + public Map getButtons() { + return Map.of( + 49, new ItemBuilder(this, Material.BARRIER, it -> { + it.setDisplayName("§cFermer"); + }) + ); + } + + @Override + public @NotNull String getName() { + return "§8Mes Homes §7(" + homes.size() + ")"; + } + + @Override + public @Nullable String getTexture() { + return null; + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGEST; + } + + @Override + public void onInventoryClick(InventoryClickEvent event) { + event.setCancelled(true); + + Player player = (Player) event.getWhoClicked(); + int slot = event.getSlot(); + + // Bouton de fermeture + if (slot == 49) { + player.closeInventory(); + return; + } + + ItemStack clickedItem = event.getCurrentItem(); + if (clickedItem == null || !clickedItem.hasItemMeta()) return; + + // Récupérer le nom du home depuis l'item + String displayName = clickedItem.getItemMeta().getDisplayName(); + if (displayName == null || displayName.isEmpty()) return; + String homeName = displayName.replace("§e", ""); + + Optional homeOpt = HomeManager.getHome(player.getUniqueId(), homeName); + if (homeOpt.isEmpty()) { + player.sendMessage("§cCe home n'existe plus !"); + player.closeInventory(); + return; + } + + Home home = homeOpt.get(); + + if (event.isShiftClick()) { + // Suppression du home + boolean success = HomeManager.deleteHome(player, homeName); + if (success) { + player.sendMessage("§cHome §e" + homeName + " §csupprimé !"); + } else { + player.sendMessage("§cImpossible de supprimer le home §e" + homeName + " §c!"); + } + player.closeInventory(); + } else { + // Téléportation au home + Location location = home.toLocation(); + if (location == null) { + player.sendMessage("§cLe monde §e" + home.getWorld() + " §cn'existe plus !"); + player.closeInventory(); + return; + } + + player.teleport(location); + player.sendMessage("§aTéléportation au home §e" + homeName + " §a!"); + player.closeInventory(); + } + } + + @Override + public void onClose(InventoryCloseEvent event) { + // Rien à faire lors de la fermeture + } + + @Override + public List getTakableSlot() { + return List.of(); + } + + @Override + public int getSizeOfItems() { + return homes.size(); + } +} From 81c1c9e11e0b9f29a3c59044dbc8c74f2e04ce5b Mon Sep 17 00:00:00 2001 From: AxenoDev Date: Sat, 7 Feb 2026 22:29:15 +0100 Subject: [PATCH 2/9] update: enhance database connection handling and remove SQLite configuration --- .../axeno/hommr/managers/DatabaseManager.java | 50 ++++++++----------- src/main/resources/config.yml | 6 --- 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/src/main/java/me/axeno/hommr/managers/DatabaseManager.java b/src/main/java/me/axeno/hommr/managers/DatabaseManager.java index 9a4ca6a..174cec5 100644 --- a/src/main/java/me/axeno/hommr/managers/DatabaseManager.java +++ b/src/main/java/me/axeno/hommr/managers/DatabaseManager.java @@ -2,18 +2,18 @@ import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; -import com.j256.ormlite.jdbc.JdbcConnectionSource; +import com.j256.ormlite.jdbc.JdbcPooledConnectionSource; import com.j256.ormlite.misc.TransactionManager; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; import lombok.Getter; import me.axeno.hommr.Hommr; import me.axeno.hommr.models.Home; +import org.bukkit.configuration.file.FileConfiguration; -import java.io.File; +import java.nio.channels.ConnectionPendingException; import java.sql.SQLException; import java.util.List; -import java.util.concurrent.Callable; public class DatabaseManager { @@ -25,46 +25,36 @@ public class DatabaseManager { * Set up the database connection and DAO for Home entities based on configuration. * * Initializes the plugin data folder if necessary, creates a JDBC connection source - * (MySQL when `database.type` is `"mysql"`, otherwise SQLite using a `homes.db` file), * and creates a Dao for accessing Home records. Ensures the Home table * exists in the database; failures during folder creation, table creation, or overall * initialization are logged. */ public void init() { try { - File dataFolder = Hommr.getInstance().getDataFolder(); - if (!dataFolder.exists()) { - boolean created = dataFolder.mkdirs(); - if (!created) { - Hommr.getInstance().getLogger().warning("Could not create plugin data folder: " + dataFolder.getAbsolutePath()); - } - } - - String type = Hommr.getInstance().getConfig().getString("database.type", "sqlite").toLowerCase(); - String databaseUrl; - String username = null; - String password = null; + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + Hommr.getInstance().getSLF4JLogger().error("Database driver not found. Please ensure the MySQL or H2 driver is included in the classpath."); + throw new RuntimeException(e); + } - if (type.equals("mysql")) { - databaseUrl = Hommr.getInstance().getConfig().getString("database.connection.url"); - username = Hommr.getInstance().getConfig().getString("database.connection.username"); - password = Hommr.getInstance().getConfig().getString("database.connection.password"); - if (databaseUrl == null || databaseUrl.isEmpty()) { - throw new IllegalArgumentException("MySQL database URL is required but not configured. Please check your config.yml."); - } - connectionSource = new JdbcConnectionSource(databaseUrl, username, password); - } else { - databaseUrl = "jdbc:sqlite:" + new File(dataFolder, "homes.db").getAbsolutePath(); - connectionSource = new JdbcConnectionSource(databaseUrl); - } + try { + FileConfiguration config = Hommr.getInstance().getConfig(); + String dbUrl = config.getString("database.connection.url"); + String dbUser = config.getString("database.connection.username"); + String dbPassword = config.getString("database.connection.password"); + connectionSource = new JdbcPooledConnectionSource(dbUrl, dbUser, dbPassword); homeDao = DaoManager.createDao(connectionSource, Home.class); - - TableUtils.createTableIfNotExists(connectionSource, Home.class); + if (!homeDao.isTableExists()) { + TableUtils.createTableIfNotExists(connectionSource, Home.class); + } } catch (SQLException e) { Hommr.getInstance().getLogger().log(java.util.logging.Level.SEVERE, "Failed to initialize database", e); throw new RuntimeException("Database initialization failed", e); + } catch (ConnectionPendingException e) { + Hommr.getInstance().getLogger().log(java.util.logging.Level.SEVERE, "Database connection is pending", e); + throw new RuntimeException("Database connection is pending", e); } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5af7390..1210533 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,12 +1,6 @@ # Hommr Configuration database: - # Database type to use for storage. - # Available options: - # - sqlite: Stores data in a local file (homes.db) within the plugin folder. No extra setup required. - # - mysql: Stores data in an external MySQL database. Requires connection details below. - type: sqlite - connection: # JDBC URL for the database connection (Required for MySQL). # Format for MySQL: jdbc:mysql://:/ From 3fa60ae72d91e234e72ef3c7bcea4a20bc329c2a Mon Sep 17 00:00:00 2001 From: AxenoDev Date: Sat, 7 Feb 2026 22:33:52 +0100 Subject: [PATCH 3/9] Revert "update: add HomeListMenu for improved home management and integrate menu-lib" This reverts commit e567f9f58f1b2d792b198a7d5425266036565d7e. modified: build.gradle modified: gradle.properties modified: src/main/java/me/axeno/hommr/Hommr.java modified: src/main/java/me/axeno/hommr/commands/HomeCommands.java deleted: src/main/java/me/axeno/hommr/menus/HomeListMenu.java --- build.gradle | 6 +- gradle.properties | 2 - src/main/java/me/axeno/hommr/Hommr.java | 3 - .../me/axeno/hommr/commands/HomeCommands.java | 37 ++-- .../me/axeno/hommr/menus/HomeListMenu.java | 164 ------------------ 5 files changed, 18 insertions(+), 194 deletions(-) delete mode 100644 src/main/java/me/axeno/hommr/menus/HomeListMenu.java diff --git a/build.gradle b/build.gradle index eb8b152..488181b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,3 @@ - import org.gradle.api.tasks.testing.logging.TestExceptionFormat - plugins { id 'java' id 'maven-publish' @@ -48,8 +46,6 @@ dependencies { implementation("org.xerial:sqlite-jdbc:${sqlite_jdbc_version}") implementation("com.mysql:mysql-connector-j:${mysql_connector_version}") - implementation("com.github.Xernas78:menu-lib:${menulib_version}") - compileOnly("org.projectlombok:lombok:${lombok_version}") annotationProcessor("org.projectlombok:lombok:${lombok_version}") @@ -79,7 +75,7 @@ tasks { useJUnitPlatform() testLogging { events("passed", "skipped", "failed") - exceptionFormat = TestExceptionFormat.FULL + exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL showStandardStreams = false } } diff --git a/gradle.properties b/gradle.properties index 55a2d56..0682288 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,8 +5,6 @@ lombok_version=1.18.38 revxrsal_lamp_version=4.0.0-rc.14 revxrsal_paper_version=4.0.0-beta.19 -menulib_version=1.3.6 - ormlite_version=6.1 sqlite_jdbc_version=3.51.1.0 mysql_connector_version=9.6.0 diff --git a/src/main/java/me/axeno/hommr/Hommr.java b/src/main/java/me/axeno/hommr/Hommr.java index 74fccb4..18b6345 100644 --- a/src/main/java/me/axeno/hommr/Hommr.java +++ b/src/main/java/me/axeno/hommr/Hommr.java @@ -1,6 +1,5 @@ package me.axeno.hommr; -import dev.xernas.menulib.MenuLib; import lombok.Getter; import me.axeno.hommr.api.HommrApi; import me.axeno.hommr.api.impl.HommrApiImpl; @@ -38,8 +37,6 @@ public void onEnable() { HomeManager.init(); - MenuLib.init(this); - this.api = new HommrApiImpl(); Bukkit.getServicesManager().register(HommrApi.class, api, this, ServicePriority.Normal); diff --git a/src/main/java/me/axeno/hommr/commands/HomeCommands.java b/src/main/java/me/axeno/hommr/commands/HomeCommands.java index eacd630..9e362ec 100644 --- a/src/main/java/me/axeno/hommr/commands/HomeCommands.java +++ b/src/main/java/me/axeno/hommr/commands/HomeCommands.java @@ -1,7 +1,6 @@ package me.axeno.hommr.commands; import me.axeno.hommr.managers.HomeManager; -import me.axeno.hommr.menus.HomeListMenu; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextDecoration; @@ -32,25 +31,23 @@ public void noArgs(Player player) { return; } - new HomeListMenu(player).open(); - -// msg(player, Component.text("Your Homes", NamedTextColor.GOLD, TextDecoration.BOLD)); -// -// for (String homeName : homes) { -// HomeManager.getHome(player.getUniqueId(), homeName).ifPresent(home -> { -// String worldInfo = home.getWorld(); -// player.sendMessage(Component.text() -// .append(Component.text(" • ", NamedTextColor.DARK_GRAY)) -// .append(Component.text(homeName, NamedTextColor.YELLOW)) -// .append(Component.text(" (" + worldInfo + ")", NamedTextColor.GRAY)) -// .build()); -// }); -// } -// -// player.sendMessage(Component.text() -// .append(Component.text(" Total: ", NamedTextColor.GOLD)) -// .append(Component.text(homes.size() + " home(s)", NamedTextColor.YELLOW)) -// .build()); + msg(player, Component.text("Your Homes", NamedTextColor.GOLD, TextDecoration.BOLD)); + + for (String homeName : homes) { + HomeManager.getHome(player.getUniqueId(), homeName).ifPresent(home -> { + String worldInfo = home.getWorld(); + player.sendMessage(Component.text() + .append(Component.text(" • ", NamedTextColor.DARK_GRAY)) + .append(Component.text(homeName, NamedTextColor.YELLOW)) + .append(Component.text(" (" + worldInfo + ")", NamedTextColor.GRAY)) + .build()); + }); + } + + player.sendMessage(Component.text() + .append(Component.text(" Total: ", NamedTextColor.GOLD)) + .append(Component.text(homes.size() + " home(s)", NamedTextColor.YELLOW)) + .build()); } @Command("home ") diff --git a/src/main/java/me/axeno/hommr/menus/HomeListMenu.java b/src/main/java/me/axeno/hommr/menus/HomeListMenu.java deleted file mode 100644 index 7560ca6..0000000 --- a/src/main/java/me/axeno/hommr/menus/HomeListMenu.java +++ /dev/null @@ -1,164 +0,0 @@ -package me.axeno.hommr.menus; - -import dev.xernas.menulib.PaginatedMenu; -import dev.xernas.menulib.utils.InventorySize; -import dev.xernas.menulib.utils.ItemBuilder; -import me.axeno.hommr.managers.HomeManager; -import me.axeno.hommr.models.Home; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryCloseEvent; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.stream.Collectors; - -public class HomeListMenu extends PaginatedMenu { - - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm"); - private final List homes; - - public HomeListMenu(Player owner) { - super(owner); - // Récupérer tous les homes du joueur - Set homeNames = HomeManager.getHomeNames(owner.getUniqueId()); - this.homes = homeNames.stream() - .map(name -> HomeManager.getHome(owner.getUniqueId(), name)) - .filter(Optional::isPresent) - .map(Optional::get) - .sorted(Comparator.comparing(Home::getName)) - .collect(Collectors.toList()); - } - - @Override - public @Nullable Material getBorderMaterial() { - return Material.GRAY_STAINED_GLASS_PANE; - } - - @Override - public @NotNull List getStaticSlots() { - return List.of(49); // Slot pour le bouton de fermeture - } - - @Override - public List getItems() { - List items = new ArrayList<>(); - for (Home home : homes) { - List lore = new ArrayList<>(); - lore.add("§7Monde: §f" + home.getWorld()); - lore.add("§7X: §f" + String.format("%.2f", home.getX())); - lore.add("§7Y: §f" + String.format("%.2f", home.getY())); - lore.add("§7Z: §f" + String.format("%.2f", home.getZ())); - lore.add("§7Créé le: §f" + DATE_FORMAT.format(new Date(home.getCreatedAt()))); - lore.add(""); - lore.add("§aCliquez pour vous téléporter"); - lore.add("§cShift + Clic pour supprimer"); - - ItemStack item = new ItemBuilder(this, Material.RED_BED, it -> { - it.setDisplayName("§e" + home.getName()); - it.setLore(lore); - }); - - items.add(item); - } - return items; - } - - @Override - public Map getButtons() { - return Map.of( - 49, new ItemBuilder(this, Material.BARRIER, it -> { - it.setDisplayName("§cFermer"); - }) - ); - } - - @Override - public @NotNull String getName() { - return "§8Mes Homes §7(" + homes.size() + ")"; - } - - @Override - public @Nullable String getTexture() { - return null; - } - - @Override - public @NotNull InventorySize getInventorySize() { - return InventorySize.LARGEST; - } - - @Override - public void onInventoryClick(InventoryClickEvent event) { - event.setCancelled(true); - - Player player = (Player) event.getWhoClicked(); - int slot = event.getSlot(); - - // Bouton de fermeture - if (slot == 49) { - player.closeInventory(); - return; - } - - ItemStack clickedItem = event.getCurrentItem(); - if (clickedItem == null || !clickedItem.hasItemMeta()) return; - - // Récupérer le nom du home depuis l'item - String displayName = clickedItem.getItemMeta().getDisplayName(); - if (displayName == null || displayName.isEmpty()) return; - String homeName = displayName.replace("§e", ""); - - Optional homeOpt = HomeManager.getHome(player.getUniqueId(), homeName); - if (homeOpt.isEmpty()) { - player.sendMessage("§cCe home n'existe plus !"); - player.closeInventory(); - return; - } - - Home home = homeOpt.get(); - - if (event.isShiftClick()) { - // Suppression du home - boolean success = HomeManager.deleteHome(player, homeName); - if (success) { - player.sendMessage("§cHome §e" + homeName + " §csupprimé !"); - } else { - player.sendMessage("§cImpossible de supprimer le home §e" + homeName + " §c!"); - } - player.closeInventory(); - } else { - // Téléportation au home - Location location = home.toLocation(); - if (location == null) { - player.sendMessage("§cLe monde §e" + home.getWorld() + " §cn'existe plus !"); - player.closeInventory(); - return; - } - - player.teleport(location); - player.sendMessage("§aTéléportation au home §e" + homeName + " §a!"); - player.closeInventory(); - } - } - - @Override - public void onClose(InventoryCloseEvent event) { - // Rien à faire lors de la fermeture - } - - @Override - public List getTakableSlot() { - return List.of(); - } - - @Override - public int getSizeOfItems() { - return homes.size(); - } -} From 9fbd0fc18af86bffec2c2da657eaed1532bbfac8 Mon Sep 17 00:00:00 2001 From: AxenoDev Date: Sat, 7 Feb 2026 22:37:29 +0100 Subject: [PATCH 4/9] update: improve database connection error handling and validate configuration --- .../axeno/hommr/managers/DatabaseManager.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/me/axeno/hommr/managers/DatabaseManager.java b/src/main/java/me/axeno/hommr/managers/DatabaseManager.java index 174cec5..b44c262 100644 --- a/src/main/java/me/axeno/hommr/managers/DatabaseManager.java +++ b/src/main/java/me/axeno/hommr/managers/DatabaseManager.java @@ -11,7 +11,6 @@ import me.axeno.hommr.models.Home; import org.bukkit.configuration.file.FileConfiguration; -import java.nio.channels.ConnectionPendingException; import java.sql.SQLException; import java.util.List; @@ -23,7 +22,7 @@ public class DatabaseManager { /** * Set up the database connection and DAO for Home entities based on configuration. - * + *

* Initializes the plugin data folder if necessary, creates a JDBC connection source * and creates a Dao for accessing Home records. Ensures the Home table * exists in the database; failures during folder creation, table creation, or overall @@ -33,7 +32,7 @@ public void init() { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { - Hommr.getInstance().getSLF4JLogger().error("Database driver not found. Please ensure the MySQL or H2 driver is included in the classpath."); + Hommr.getInstance().getSLF4JLogger().error("MySQL database driver not found. Please ensure the MySQL driver is included in the classpath."); throw new RuntimeException(e); } @@ -42,6 +41,11 @@ public void init() { String dbUrl = config.getString("database.connection.url"); String dbUser = config.getString("database.connection.username"); String dbPassword = config.getString("database.connection.password"); + + if (dbUrl == null || dbUrl.isEmpty()) { + throw new IllegalStateException("Database URL is not configured. Please set 'database.connection.url' in config.yml"); + } + connectionSource = new JdbcPooledConnectionSource(dbUrl, dbUser, dbPassword); homeDao = DaoManager.createDao(connectionSource, Home.class); @@ -52,16 +56,13 @@ public void init() { } catch (SQLException e) { Hommr.getInstance().getLogger().log(java.util.logging.Level.SEVERE, "Failed to initialize database", e); throw new RuntimeException("Database initialization failed", e); - } catch (ConnectionPendingException e) { - Hommr.getInstance().getLogger().log(java.util.logging.Level.SEVERE, "Database connection is pending", e); - throw new RuntimeException("Database connection is pending", e); } } /** * Closes the underlying database connection source and releases related resources. - * - * If an error occurs while closing, the exception is caught and a warning is logged. + *

+ * If an error occurs while closing, the exception is caught and a warning is logged. */ public void close() { if (connectionSource != null) { @@ -86,7 +87,7 @@ public List getAllHomes() throws SQLException { /** * Replaces all stored Home records with the provided list. - * + *

* Clears the Home table and inserts the given homes in a single batch operation. * * @param homes the list of Home objects to persist (may be empty) From 3da35bc261e805cb47aa9ab93fc958485c7c7dcd Mon Sep 17 00:00:00 2001 From: AxenoDev Date: Sun, 8 Feb 2026 13:30:27 +0100 Subject: [PATCH 5/9] update: add MySQL configuration and refactor database connection initialization --- build.gradle | 1 + .../axeno/hommr/managers/DatabaseManager.java | 32 +++++++++++-------- .../hommr/managers/DatabaseManagerTest.java | 25 +++------------ src/test/resources/config.yml | 10 ++++++ src/test/resources/paper-plugin.yml | 9 ++++++ 5 files changed, 43 insertions(+), 34 deletions(-) create mode 100644 src/test/resources/config.yml create mode 100644 src/test/resources/paper-plugin.yml diff --git a/build.gradle b/build.gradle index 488181b..99b56b9 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,7 @@ dependencies { testImplementation("com.j256.ormlite:ormlite-jdbc:${ormlite_version}") testImplementation("org.xerial:sqlite-jdbc:${sqlite_jdbc_version}") + testImplementation("com.h2database:h2:2.2.224") testCompileOnly("org.projectlombok:lombok:${lombok_version}") testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") diff --git a/src/main/java/me/axeno/hommr/managers/DatabaseManager.java b/src/main/java/me/axeno/hommr/managers/DatabaseManager.java index b44c262..58b4c18 100644 --- a/src/main/java/me/axeno/hommr/managers/DatabaseManager.java +++ b/src/main/java/me/axeno/hommr/managers/DatabaseManager.java @@ -20,15 +20,7 @@ public class DatabaseManager { @Getter private Dao homeDao; - /** - * Set up the database connection and DAO for Home entities based on configuration. - *

- * Initializes the plugin data folder if necessary, creates a JDBC connection source - * and creates a Dao for accessing Home records. Ensures the Home table - * exists in the database; failures during folder creation, table creation, or overall - * initialization are logged. - */ - public void init() { + public void init(String dbUrl, String dbUser, String dbPassword) { try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) { @@ -37,11 +29,6 @@ public void init() { } try { - FileConfiguration config = Hommr.getInstance().getConfig(); - String dbUrl = config.getString("database.connection.url"); - String dbUser = config.getString("database.connection.username"); - String dbPassword = config.getString("database.connection.password"); - if (dbUrl == null || dbUrl.isEmpty()) { throw new IllegalStateException("Database URL is not configured. Please set 'database.connection.url' in config.yml"); } @@ -59,6 +46,23 @@ public void init() { } } + /** + * Set up the database connection and DAO for Home entities based on configuration. + *

+ * Initializes the plugin data folder if necessary, creates a JDBC connection source + * and creates a Dao for accessing Home records. Ensures the Home table + * exists in the database; failures during folder creation, table creation, or overall + * initialization are logged. + */ + public void init() { + FileConfiguration config = Hommr.getInstance().getConfig(); + String dbUrl = config.getString("database.connection.url"); + String dbUser = config.getString("database.connection.username", ""); + String dbPassword = config.getString("database.connection.password", ""); + + init(dbUrl, dbUser, dbPassword); + } + /** * Closes the underlying database connection source and releases related resources. *

diff --git a/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java b/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java index 0738e78..9dd333e 100644 --- a/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java +++ b/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java @@ -1,11 +1,8 @@ package me.axeno.hommr.managers; -import com.j256.ormlite.dao.Dao; -import com.j256.ormlite.support.ConnectionSource; import me.axeno.hommr.Hommr; import me.axeno.hommr.models.Home; import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.plugin.PluginDescriptionFile; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -15,7 +12,6 @@ import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; -import java.io.File; import java.nio.file.Path; import java.sql.SQLException; import java.util.ArrayList; @@ -45,8 +41,10 @@ class DatabaseManagerTest { private MockedStatic hommrMockedStatic; @BeforeEach - void setUp() { + void setUp() throws SQLException { + // Use H2 in-memory database for testing databaseManager = new DatabaseManager(); + databaseManager.init("jdbc:sqlite:database.db", "sa", ""); hommrMockedStatic = mockStatic(Hommr.class); hommrMockedStatic.when(Hommr::getInstance).thenReturn(mockPlugin); @@ -54,7 +52,6 @@ void setUp() { lenient().when(mockPlugin.getDataFolder()).thenReturn(tempDir.toFile()); lenient().when(mockPlugin.getConfig()).thenReturn(mockConfig); lenient().when(mockPlugin.getLogger()).thenReturn(mockLogger); - lenient().when(mockConfig.getString("database.type", "sqlite")).thenReturn("sqlite"); } @AfterEach @@ -69,17 +66,11 @@ void tearDown() { @Test void testInitWithSQLiteCreatesDatabase() { - databaseManager.init(); - assertNotNull(databaseManager.getHomeDao()); - File dbFile = new File(tempDir.toFile(), "homes.db"); - assertTrue(dbFile.exists()); } @Test void testSaveAndGetAllHomes() throws SQLException { - databaseManager.init(); - List homesToSave = new ArrayList<>(); homesToSave.add(createTestHome(UUID.randomUUID(), "home1")); homesToSave.add(createTestHome(UUID.randomUUID(), "home2")); @@ -94,8 +85,6 @@ void testSaveAndGetAllHomes() throws SQLException { @Test void testSaveAllHomesClearsExistingHomes() throws SQLException { - databaseManager.init(); - List firstBatch = new ArrayList<>(); firstBatch.add(createTestHome(UUID.randomUUID(), "home1")); firstBatch.add(createTestHome(UUID.randomUUID(), "home2")); @@ -108,13 +97,11 @@ void testSaveAllHomesClearsExistingHomes() throws SQLException { List retrievedHomes = databaseManager.getAllHomes(); assertEquals(1, retrievedHomes.size()); - assertEquals("home3", retrievedHomes.get(0).getName()); + assertEquals("home3", retrievedHomes.getFirst().getName()); } @Test void testSaveAllHomesPreservesHomeData() throws SQLException { - databaseManager.init(); - UUID ownerId = UUID.randomUUID(); Home originalHome = new Home( 0, @@ -133,7 +120,7 @@ void testSaveAllHomesPreservesHomeData() throws SQLException { List retrievedHomes = databaseManager.getAllHomes(); assertEquals(1, retrievedHomes.size()); - Home retrievedHome = retrievedHomes.get(0); + Home retrievedHome = retrievedHomes.getFirst(); assertEquals(ownerId, retrievedHome.getOwner()); assertEquals("testHome", retrievedHome.getName()); assertEquals("world", retrievedHome.getWorld()); @@ -146,8 +133,6 @@ void testSaveAllHomesPreservesHomeData() throws SQLException { @Test void testCloseDoesNotThrowException() { - databaseManager.init(); - assertDoesNotThrow(() -> databaseManager.close()); } diff --git a/src/test/resources/config.yml b/src/test/resources/config.yml new file mode 100644 index 0000000..1210533 --- /dev/null +++ b/src/test/resources/config.yml @@ -0,0 +1,10 @@ +# Hommr Configuration + +database: + connection: + # JDBC URL for the database connection (Required for MySQL). + # Format for MySQL: jdbc:mysql://:/ + # Example: jdbc:mysql://localhost:3306/hommr + url: jdbc:mysql://localhost:3306/hommr + username: "" + password: "" diff --git a/src/test/resources/paper-plugin.yml b/src/test/resources/paper-plugin.yml new file mode 100644 index 0000000..294bc0e --- /dev/null +++ b/src/test/resources/paper-plugin.yml @@ -0,0 +1,9 @@ +name: Hommr +version: ${version} +main: me.axeno.hommr.Hommr +api-version: ${minecraft_version} +prefix: Hommr +load: STARTUP +authors: [ AxenoDev ] +description: Easily set, teleport, and manage your homes. +website: https://axeno.me From 8cd38305e3849c42b376a83011ebdb67a25edbef Mon Sep 17 00:00:00 2001 From: AxenoDev Date: Sun, 8 Feb 2026 13:36:19 +0100 Subject: [PATCH 6/9] update: change SQLite database initialization to use in-memory database for testing --- src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java b/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java index 9dd333e..9675016 100644 --- a/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java +++ b/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java @@ -44,7 +44,7 @@ class DatabaseManagerTest { void setUp() throws SQLException { // Use H2 in-memory database for testing databaseManager = new DatabaseManager(); - databaseManager.init("jdbc:sqlite:database.db", "sa", ""); + databaseManager.init("jdbc:sqlite::memory:", "", ""); hommrMockedStatic = mockStatic(Hommr.class); hommrMockedStatic.when(Hommr::getInstance).thenReturn(mockPlugin); From 1275eac82405f0e910be1e163cc9b005678afae0 Mon Sep 17 00:00:00 2001 From: AxenoDev Date: Sun, 8 Feb 2026 13:36:33 +0100 Subject: [PATCH 7/9] update: change SQLite database initialization to use in-memory database for testing --- src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java b/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java index 9675016..af05c58 100644 --- a/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java +++ b/src/test/java/me/axeno/hommr/managers/DatabaseManagerTest.java @@ -42,7 +42,7 @@ class DatabaseManagerTest { @BeforeEach void setUp() throws SQLException { - // Use H2 in-memory database for testing + // Use SQLite in-memory database for testing databaseManager = new DatabaseManager(); databaseManager.init("jdbc:sqlite::memory:", "", ""); From 6ea581730ef5d0e93a0bdeee23dddb8d799ac3d0 Mon Sep 17 00:00:00 2001 From: AxenoDev Date: Sun, 8 Feb 2026 13:38:26 +0100 Subject: [PATCH 8/9] update: remove H2 database dependency from test implementation --- build.gradle | 1 - src/test/resources/config.yml | 10 ---------- src/test/resources/paper-plugin.yml | 9 --------- 3 files changed, 20 deletions(-) delete mode 100644 src/test/resources/config.yml delete mode 100644 src/test/resources/paper-plugin.yml diff --git a/build.gradle b/build.gradle index 99b56b9..488181b 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,6 @@ dependencies { testImplementation("com.j256.ormlite:ormlite-jdbc:${ormlite_version}") testImplementation("org.xerial:sqlite-jdbc:${sqlite_jdbc_version}") - testImplementation("com.h2database:h2:2.2.224") testCompileOnly("org.projectlombok:lombok:${lombok_version}") testAnnotationProcessor("org.projectlombok:lombok:${lombok_version}") diff --git a/src/test/resources/config.yml b/src/test/resources/config.yml deleted file mode 100644 index 1210533..0000000 --- a/src/test/resources/config.yml +++ /dev/null @@ -1,10 +0,0 @@ -# Hommr Configuration - -database: - connection: - # JDBC URL for the database connection (Required for MySQL). - # Format for MySQL: jdbc:mysql://:/ - # Example: jdbc:mysql://localhost:3306/hommr - url: jdbc:mysql://localhost:3306/hommr - username: "" - password: "" diff --git a/src/test/resources/paper-plugin.yml b/src/test/resources/paper-plugin.yml deleted file mode 100644 index 294bc0e..0000000 --- a/src/test/resources/paper-plugin.yml +++ /dev/null @@ -1,9 +0,0 @@ -name: Hommr -version: ${version} -main: me.axeno.hommr.Hommr -api-version: ${minecraft_version} -prefix: Hommr -load: STARTUP -authors: [ AxenoDev ] -description: Easily set, teleport, and manage your homes. -website: https://axeno.me From 8ac6d7ecb20e9cb7732df434e8a6bcb19ed6edfd Mon Sep 17 00:00:00 2001 From: AxenoDev Date: Sun, 8 Feb 2026 13:40:14 +0100 Subject: [PATCH 9/9] update: enhance MySQL database initialization with driver loading and URL validation --- .../axeno/hommr/managers/DatabaseManager.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/axeno/hommr/managers/DatabaseManager.java b/src/main/java/me/axeno/hommr/managers/DatabaseManager.java index 58b4c18..da74dc7 100644 --- a/src/main/java/me/axeno/hommr/managers/DatabaseManager.java +++ b/src/main/java/me/axeno/hommr/managers/DatabaseManager.java @@ -21,18 +21,20 @@ public class DatabaseManager { private Dao homeDao; public void init(String dbUrl, String dbUser, String dbPassword) { - try { - Class.forName("com.mysql.cj.jdbc.Driver"); - } catch (ClassNotFoundException e) { - Hommr.getInstance().getSLF4JLogger().error("MySQL database driver not found. Please ensure the MySQL driver is included in the classpath."); - throw new RuntimeException(e); + if (dbUrl == null || dbUrl.isEmpty()) { + throw new IllegalStateException("Database URL is not configured. Please set 'database.connection.url' in config.yml"); } - try { - if (dbUrl == null || dbUrl.isEmpty()) { - throw new IllegalStateException("Database URL is not configured. Please set 'database.connection.url' in config.yml"); + if (dbUrl.startsWith("jbdc:mysql:")) { + try { + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + Hommr.getInstance().getSLF4JLogger().error("MySQL database driver not found. Please ensure the MySQL driver is included in the classpath."); + throw new RuntimeException(e); } + } + try { connectionSource = new JdbcPooledConnectionSource(dbUrl, dbUser, dbPassword); homeDao = DaoManager.createDao(connectionSource, Home.class);