From 6fcfdb3377bb9f7222f83db2dcdfe4df60e193af Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Tue, 17 Feb 2026 12:23:29 +0100 Subject: [PATCH 01/52] Fix soul chestplate altar crafting --- .../openmc/core/features/dream/mecanism/altar/AltarRecipes.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/altar/AltarRecipes.java b/src/main/java/fr/openmc/core/features/dream/mecanism/altar/AltarRecipes.java index 3904d08de..b053c56e2 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/altar/AltarRecipes.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/altar/AltarRecipes.java @@ -19,7 +19,7 @@ public enum AltarRecipes { 10 ), SOUL_CHESTPLATE( - DreamItemRegistry.getByName("omc_dream:old_creaking_chesplate"), + DreamItemRegistry.getByName("omc_dream:old_creaking_chestplate"), DreamItemRegistry.getByName("omc_dream:soul_chestplate"), 10 ), From d89c65fe41c2e364b9de8e11fc204b07554a2820 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Feb 2026 12:56:40 +0100 Subject: [PATCH 02/52] Change SoulAxe rarity from COMMON to RARE --- .../core/features/dream/registries/items/tools/SoulAxe.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/openmc/core/features/dream/registries/items/tools/SoulAxe.java b/src/main/java/fr/openmc/core/features/dream/registries/items/tools/SoulAxe.java index aae13e003..16f619070 100644 --- a/src/main/java/fr/openmc/core/features/dream/registries/items/tools/SoulAxe.java +++ b/src/main/java/fr/openmc/core/features/dream/registries/items/tools/SoulAxe.java @@ -13,7 +13,7 @@ public SoulAxe(String name) { @Override public DreamRarity getRarity() { - return DreamRarity.COMMON; + return DreamRarity.RARE; } @Override From 728e6778610a3b710797e03c5c32a4ff133567e0 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:27:14 +0100 Subject: [PATCH 03/52] =?UTF-8?q?Correctif=20de=20la=20possibilit=C3=A9=20?= =?UTF-8?q?de=20se=20faire=20de=20l'argent=20a=20l'infini=20(#1158)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: claim dupli * fix: Cannot invoke "String.isEmpty()" because "content" is null * fix: FancyNpcsPlugin is null --- .../city/actions/CityUnclaimAction.java | 22 ++++++++++-------- .../features/city/menu/CityChunkMenu.java | 21 +++++++++++++---- .../scoreboards/sb/MainScoreboard.java | 23 +++++++++++-------- .../leaderboards/LeaderboardManager.java | 15 ++++++++++++ 4 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/city/actions/CityUnclaimAction.java b/src/main/java/fr/openmc/core/features/city/actions/CityUnclaimAction.java index 2bdacdb99..10b6cbbf3 100644 --- a/src/main/java/fr/openmc/core/features/city/actions/CityUnclaimAction.java +++ b/src/main/java/fr/openmc/core/features/city/actions/CityUnclaimAction.java @@ -9,6 +9,7 @@ import fr.openmc.core.utils.messages.MessagesManager; import fr.openmc.core.utils.messages.Prefix; import net.kyori.adventure.text.Component; +import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -26,7 +27,7 @@ public static int calculateAywenite(int chunkCount) { public static void startUnclaim(Player sender, int chunkX, int chunkZ) { City city = CityManager.getPlayerCity(sender.getUniqueId()); - org.bukkit.World bWorld = sender.getWorld(); + World bWorld = sender.getWorld(); if (!bWorld.getName().equals("world")) { MessagesManager.sendMessage(sender, Component.text("Tu ne peux pas étendre ta ville ici"), Prefix.CITY, MessageType.ERROR, false); return; @@ -42,14 +43,17 @@ public static void startUnclaim(Player sender, int chunkX, int chunkZ) { return; } - int price = calculatePrice(city.getChunks().size()); - int ayweniteNb = calculateAywenite(city.getChunks().size()); - - EconomyManager.addBalance(sender.getUniqueId(), price, "Unclaim de chunk de ville"); - ItemStack aywenite = ayweniteItemStack.clone(); - aywenite.setAmount(ayweniteNb); - for (ItemStack item : ItemUtils.splitAmountIntoStack(aywenite)) { - sender.dropItem(item); + // si on unclaim des claims gratuits on ne rend rien, sinon on rend une partie de l'argent et d'aywenite + if (city.getChunks().size() > CityCreateAction.FREE_CLAIMS+1) { + int price = calculatePrice(city.getChunks().size()); + int ayweniteNb = calculateAywenite(city.getChunks().size()); + + EconomyManager.addBalance(sender.getUniqueId(), price, "Unclaim de chunk de ville"); + ItemStack aywenite = ayweniteItemStack.clone(); + aywenite.setAmount(ayweniteNb); + for (ItemStack item : ItemUtils.splitAmountIntoStack(aywenite)) { + sender.dropItem(item); + } } city.removeChunk(chunkX, chunkZ); diff --git a/src/main/java/fr/openmc/core/features/city/menu/CityChunkMenu.java b/src/main/java/fr/openmc/core/features/city/menu/CityChunkMenu.java index 553bf95fa..b444fdaa2 100644 --- a/src/main/java/fr/openmc/core/features/city/menu/CityChunkMenu.java +++ b/src/main/java/fr/openmc/core/features/city/menu/CityChunkMenu.java @@ -11,6 +11,7 @@ import fr.openmc.core.features.city.CityManager; import fr.openmc.core.features.city.CityPermission; import fr.openmc.core.features.city.actions.CityClaimAction; +import fr.openmc.core.features.city.actions.CityCreateAction; import fr.openmc.core.features.city.actions.CityUnclaimAction; import fr.openmc.core.features.economy.EconomyManager; import fr.openmc.core.utils.ChunkInfo; @@ -264,9 +265,9 @@ private ItemBuilder createProtectedChunkItem(Material material, int chunkX, int } private ItemBuilder createPlayerCityChunkItem(Material material, City city, int chunkX, int chunkZ) { - return new ItemBuilder(this, material, itemMeta -> { - itemMeta.displayName(Component.text("§9Claim de votre ville")); - itemMeta.lore(List.of( + List lore; + if (city.getChunks().size() > CityCreateAction.FREE_CLAIMS+1) { + lore = List.of( Component.text("§7Ville : §d" + city.getName()), Component.text("§7Position : §f" + chunkX + ", " + chunkZ), Component.empty(), @@ -275,7 +276,19 @@ private ItemBuilder createPlayerCityChunkItem(Material material, City city, int Component.text("§8- §d" + CityUnclaimAction.calculateAywenite(playerCity.getChunks().size()) + " d'Aywenite"), Component.empty(), Component.text("§e§lCLIQUEZ POUR UNCLAIM") - )); + ); + } else { + lore = List.of( + Component.text("§7Ville : §d" + city.getName()), + Component.text("§7Position : §f" + chunkX + ", " + chunkZ), + Component.empty(), + Component.text("§e§lCLIQUEZ POUR UNCLAIM") + ); + } + + return new ItemBuilder(this, material, itemMeta -> { + itemMeta.displayName(Component.text("§9Claim de votre ville")); + itemMeta.lore(lore); }).setOnClick(event -> handleChunkUnclaimClick(player, chunkX, chunkZ, hasPermissionClaim)); } diff --git a/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java b/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java index 89e7b63db..33ba1ebc2 100644 --- a/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java +++ b/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java @@ -3,6 +3,7 @@ import de.oliver.fancynpcs.api.FancyNpcsPlugin; import de.oliver.fancynpcs.api.Npc; import de.oliver.fancynpcs.api.NpcManager; +import fr.openmc.api.hooks.FancyNpcsHook; import fr.openmc.api.hooks.LuckPermsHook; import fr.openmc.api.hooks.WorldGuardHook; import fr.openmc.api.scoreboard.SternalBoard; @@ -61,9 +62,6 @@ public void update(Player player, SternalBoard board) { } public static List getDefaultLines(Player player) { - NpcManager npcManager = FancyNpcsPlugin.get().getNpcManager(); - Npc halloweenNPC = npcManager.getNpc("halloween_pumpkin_deposit_npc"); - Component rank = LuckPermsHook.isHasLuckPerms() ? Component.text(LuckPermsHook.getFormattedPAPIPrefix(player)) : Component.text(textToSmall("aucun")).color(TextColor.color(0xFF1FCC)); @@ -102,13 +100,18 @@ public static List getDefaultLines(Player player) { .appendSpace() .append(text(textToSmall(location)).color(TextColor.color(0xFF06DC))) ); - if (halloweenNPC != null) { - String pumpkinCount = EconomyManager.getFormattedSimplifiedNumber(HalloweenManager.getPumpkinCount(player.getUniqueId())); - lines.add(text(" • ", NamedTextColor.DARK_GRAY) - .append(text(textToSmall("citrouilles:"), NamedTextColor.GRAY)) - .appendSpace() - .append(text(textToSmall(pumpkinCount)).color(TextColor.color(0xFF7518))) - ); + + if (FancyNpcsHook.isHasFancyNpc()) { + NpcManager npcManager = FancyNpcsPlugin.get().getNpcManager(); + Npc halloweenNPC = npcManager.getNpc("halloween_pumpkin_deposit_npc"); + if (halloweenNPC != null) { + String pumpkinCount = EconomyManager.getFormattedSimplifiedNumber(HalloweenManager.getPumpkinCount(player.getUniqueId())); + lines.add(text(" • ", NamedTextColor.DARK_GRAY) + .append(text(textToSmall("citrouilles:"), NamedTextColor.GRAY)) + .appendSpace() + .append(text(textToSmall(pumpkinCount)).color(TextColor.color(0xFF7518))) + ); + } } lines.add(newline()); diff --git a/src/main/java/fr/openmc/core/features/leaderboards/LeaderboardManager.java b/src/main/java/fr/openmc/core/features/leaderboards/LeaderboardManager.java index fd7da9e8d..fa688a272 100644 --- a/src/main/java/fr/openmc/core/features/leaderboards/LeaderboardManager.java +++ b/src/main/java/fr/openmc/core/features/leaderboards/LeaderboardManager.java @@ -91,6 +91,9 @@ public static Component createContributorsTextLeaderboard() { int rank = entry.getKey(); String contributorName = entry.getValue().getKey(); ContributorStats stats = entry.getValue().getValue(); + + if (contributorName == null || stats == null) continue; + int addLines = stats.added(); int removeLines = stats.removed(); Component line = Component.text("\n#") @@ -126,6 +129,9 @@ public static Component createMoneyTextLeaderboard() { int rank = entry.getKey(); String playerName = entry.getValue().getKey(); String money = entry.getValue().getValue(); + + if (playerName == null || money == null) continue; + Component line = Component.text("\n#") .color(getRankColor(rank)) .append(Component.text(rank).color(getRankColor(rank))) @@ -157,6 +163,9 @@ public static Component createCityMoneyTextLeaderboard() { int rank = entry.getKey(); String cityName = entry.getValue().getKey(); String money = entry.getValue().getValue(); + + if (cityName == null || money == null) continue; + Component line = Component.text("\n#") .color(getRankColor(rank)) .append(Component.text(rank).color(getRankColor(rank))) @@ -188,6 +197,9 @@ public static Component createPlayTimeTextLeaderboard() { int rank = entry.getKey(); String playerName = entry.getValue().getKey(); String time = entry.getValue().getValue(); + + if (playerName == null || time == null) continue; + Component line = Component.text("\n#") .color(getRankColor(rank)) .append(Component.text(rank).color(getRankColor(rank))) @@ -214,6 +226,9 @@ public static Component createPumpkinCountTextLeaderboard() { int rank = entry.getKey(); String playerName = entry.getValue().getKey(); String pumpkinCount = entry.getValue().getValue(); + + if (playerName == null || pumpkinCount == null) continue; + Component line = Component.text("\n#") .color(getRankColor(rank)) .append(Component.text(rank).color(getRankColor(rank))) From d139ae9eff02c02e6bb46387335fa468413a838c Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Tue, 24 Feb 2026 16:30:22 +0100 Subject: [PATCH 04/52] fix: incorrect singularity transfer (#1157) --- src/main/java/fr/openmc/core/features/dream/DreamManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/fr/openmc/core/features/dream/DreamManager.java b/src/main/java/fr/openmc/core/features/dream/DreamManager.java index edf3d859e..e4fdcebc9 100644 --- a/src/main/java/fr/openmc/core/features/dream/DreamManager.java +++ b/src/main/java/fr/openmc/core/features/dream/DreamManager.java @@ -43,6 +43,7 @@ import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; @@ -232,6 +233,8 @@ public static void addDreamPlayer(Player player, Location oldLocation) throws IO } public static void removeDreamPlayer(Player player, Location dreamLocation) { + player.closeInventory(); + DreamPlayer dreamPlayer = dreamPlayerData.remove(player.getUniqueId()); playerSaveData.remove(player.getUniqueId()); From e6b919e749d00c5d17f27cc1242063281c259553 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 27 Feb 2026 18:26:39 +0100 Subject: [PATCH 05/52] =?UTF-8?q?Refonte=20du=20principe=20pour=20aller=20?= =?UTF-8?q?dans=20la=20dimension=20des=20r=C3=AAves=20(#1156)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: dream sleep (100%) * rework: sleep to dream --- .../listeners/dream/PlayerSleepListener.java | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerSleepListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerSleepListener.java index c3a2a52c0..744175869 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerSleepListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerSleepListener.java @@ -8,62 +8,56 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerBedEnterEvent; +import org.bukkit.event.player.PlayerBedLeaveEvent; import org.bukkit.event.world.TimeSkipEvent; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitScheduler; import java.util.HashSet; import java.util.Random; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; public class PlayerSleepListener implements Listener { - private final Set playersDreaming = new HashSet<>(); + private final Set isPlayerSleeping = new HashSet<>(); @EventHandler - public void onPlayerSleep(PlayerBedEnterEvent event) { + public void onPlayerEnterBed(PlayerBedEnterEvent event) { Player player = event.getPlayer(); if (!event.getBedEnterResult().equals(PlayerBedEnterEvent.BedEnterResult.OK)) return; - if (playersDreaming.contains(player.getUniqueId())) return; - - Random random = new Random(); - double randomValue = random.nextDouble(); - - if (randomValue < DreamManager.calculateDreamProbability(player)) return; - - player.addPotionEffect(new PotionEffect( - PotionEffectType.NAUSEA, - 20 * 10, - 1, - false, - false, - false - )); - playersDreaming.add(player.getUniqueId()); - + if (isPlayerSleeping.contains(player)) return; + isPlayerSleeping.add(player); + } + @EventHandler + public void onPlayerLeaveBed(PlayerBedLeaveEvent event) { + isPlayerSleeping.remove(event.getPlayer()); } @EventHandler public void onNightSkip(TimeSkipEvent event) { - for (UUID uuid : playersDreaming) { - Player player = Bukkit.getPlayer(uuid); - if (player == null) continue; - DBDreamPlayer dbDreamPlayer = DreamManager.getCacheDreamPlayer(player); - new BukkitRunnable() { - @Override - public void run() { + if (event.getSkipReason() == TimeSkipEvent.SkipReason.NIGHT_SKIP) { + if (isPlayerSleeping.isEmpty()) { + return; + } + for (Player player : isPlayerSleeping) { + if (ThreadLocalRandom.current().nextDouble() < DreamManager.calculateDreamProbability(player)) { + Random r = new Random(); + DBDreamPlayer dbDreamPlayer = DreamManager.getCacheDreamPlayer(player); if (dbDreamPlayer == null || (dbDreamPlayer.getDreamX() == null || dbDreamPlayer.getDreamY() == null || dbDreamPlayer.getDreamZ() == null)) { DreamManager.tpPlayerDream(player); } else { DreamManager.tpPlayerToLastDreamLocation(player); } } - }.runTaskLater(OMCPlugin.getInstance(), 20L * 5); + } + + isPlayerSleeping.clear(); } - playersDreaming.clear(); } } From d23de02ecd5261e830e99a42e1b853e6cf4b07c4 Mon Sep 17 00:00:00 2001 From: Gtol <162237671+gtolontop@users.noreply.github.com> Date: Wed, 11 Mar 2026 17:19:03 +0100 Subject: [PATCH 06/52] fix: metal detector chest spawning only in +x +z direction (#1169) Fixes #1121 - findRandomChestLocation was using nextInt(20) for both dx and dz, restricting chest spawns to the north-east quadrant only. Changed to nextInt(41) - 20 so chests can appear in all four directions. --- .../dream/mecanism/metaldetector/MetalDetectorListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/metaldetector/MetalDetectorListener.java b/src/main/java/fr/openmc/core/features/dream/mecanism/metaldetector/MetalDetectorListener.java index ee322b4d2..d3d17e093 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/metaldetector/MetalDetectorListener.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/metaldetector/MetalDetectorListener.java @@ -115,8 +115,8 @@ public static Location findRandomChestLocation(Location origin) { Random random = new Random(); for (int i = 0; i < 30; i++) { - int dx = random.nextInt(20); - int dz = random.nextInt(20); + int dx = random.nextInt(41) - 20; + int dz = random.nextInt(41) - 20; Location tryLoc = origin.clone().add(dx, 0, dz); int y = world.getHighestBlockYAt(tryLoc); tryLoc.setY(y); @@ -126,6 +126,6 @@ public static Location findRandomChestLocation(Location origin) { } } - return origin.clone().add(5, 0, 5); + return origin.clone().add(random.nextInt(41) - 20, 0, random.nextInt(41) - 20); } } From ba318cdc47ede88caa07248e153d5c1dbec0518e Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 13 Mar 2026 06:48:33 +0100 Subject: [PATCH 07/52] Add tests methods in contributing.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 46f8f9b12..c832f052d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -68,5 +68,6 @@ Les noms doivent être en anglais, peu importe la chose nommée. | Package | Toujours en miniscules et tous les mots sont collés sans caractère entre (pas d'`_`). Le nom doit être simple et sans caractères spéciaux (uniquement les caractères ASCII, donc pas d'accents). Le nom du package doit au possible rester un seul mot. | `fr.communaywen.commands` | | Classes, Interfaces, Enums, Records, Annotations | Toujours en PascalCase. Utilisez seulement des noms. Évitez les acronymes ou abréviations. | `class SpawnManager;` | | Methodes | Son nom commence par un verbe. En `camelCase` | `getInstance()` `clone()` | +| Methodes de Tests | Son nom commence par test + une méthode testée. `testFormat_avoid0()` | `testGetNamedTextColor_success`| | Variables | Toujours en `camelCase`, évitez les abréviations et les noms raccourcis comme `nbr`. Pas d'`_` ou de `$` au début. L'utilité de la variable devrait être compréhensible en regardant le nom. | `int numberOfPlayers` `String playerName` | | Constantes et membres d'enums | Les constantes dont la déclaration commence par `static final` sont nommées en UPPER_SNAKE_CASE, avec comme pour les variables, un nom qui décrit clairement leur utilité. | `static final int MIN_WIDTH = 4;` | From 356a7c64e28fa409c621c7be008fce31eb8bd1db Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 13 Mar 2026 06:49:23 +0100 Subject: [PATCH 08/52] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c832f052d..c2e0f425a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -68,6 +68,6 @@ Les noms doivent être en anglais, peu importe la chose nommée. | Package | Toujours en miniscules et tous les mots sont collés sans caractère entre (pas d'`_`). Le nom doit être simple et sans caractères spéciaux (uniquement les caractères ASCII, donc pas d'accents). Le nom du package doit au possible rester un seul mot. | `fr.communaywen.commands` | | Classes, Interfaces, Enums, Records, Annotations | Toujours en PascalCase. Utilisez seulement des noms. Évitez les acronymes ou abréviations. | `class SpawnManager;` | | Methodes | Son nom commence par un verbe. En `camelCase` | `getInstance()` `clone()` | -| Methodes de Tests | Son nom commence par test + une méthode testée. `testFormat_avoid0()` | `testGetNamedTextColor_success`| +| Methodes de Tests | Son nom commence par test + une méthode testée. | `testFormat_avoid0()` `testGetNamedTextColor_success`| | Variables | Toujours en `camelCase`, évitez les abréviations et les noms raccourcis comme `nbr`. Pas d'`_` ou de `$` au début. L'utilité de la variable devrait être compréhensible en regardant le nom. | `int numberOfPlayers` `String playerName` | | Constantes et membres d'enums | Les constantes dont la déclaration commence par `static final` sont nommées en UPPER_SNAKE_CASE, avec comme pour les variables, un nom qui décrit clairement leur utilité. | `static final int MIN_WIDTH = 4;` | From 716d7fd7495e0aff2e19ccac8bed5f86b37f8687 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 13 Mar 2026 06:49:45 +0100 Subject: [PATCH 09/52] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c2e0f425a..59efa4a56 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -68,6 +68,6 @@ Les noms doivent être en anglais, peu importe la chose nommée. | Package | Toujours en miniscules et tous les mots sont collés sans caractère entre (pas d'`_`). Le nom doit être simple et sans caractères spéciaux (uniquement les caractères ASCII, donc pas d'accents). Le nom du package doit au possible rester un seul mot. | `fr.communaywen.commands` | | Classes, Interfaces, Enums, Records, Annotations | Toujours en PascalCase. Utilisez seulement des noms. Évitez les acronymes ou abréviations. | `class SpawnManager;` | | Methodes | Son nom commence par un verbe. En `camelCase` | `getInstance()` `clone()` | -| Methodes de Tests | Son nom commence par test + une méthode testée. | `testFormat_avoid0()` `testGetNamedTextColor_success`| +| Methodes de Tests | Son nom commence par test + une méthode testée. | `testFormat_avoid0()` `testGetNamedTextColor_success()`| | Variables | Toujours en `camelCase`, évitez les abréviations et les noms raccourcis comme `nbr`. Pas d'`_` ou de `$` au début. L'utilité de la variable devrait être compréhensible en regardant le nom. | `int numberOfPlayers` `String playerName` | | Constantes et membres d'enums | Les constantes dont la déclaration commence par `static final` sont nommées en UPPER_SNAKE_CASE, avec comme pour les variables, un nom qui décrit clairement leur utilité. | `static final int MIN_WIDTH = 4;` | From 505a0a4e518e52f932522191cc4897e50654dcfa Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sat, 14 Mar 2026 11:08:28 +0100 Subject: [PATCH 10/52] fix Double is null (#1192) --- .../sub/notation/menu/NotationDialog.java | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/city/sub/notation/menu/NotationDialog.java b/src/main/java/fr/openmc/core/features/city/sub/notation/menu/NotationDialog.java index 04b6d3b0f..c36447249 100644 --- a/src/main/java/fr/openmc/core/features/city/sub/notation/menu/NotationDialog.java +++ b/src/main/java/fr/openmc/core/features/city/sub/notation/menu/NotationDialog.java @@ -104,9 +104,13 @@ public static DialogBody lineCityNotation(City city, String weekStr) { Component base = Component.empty(); if (notation != null) { - String activity = String.format("%.2f/" + NotationNote.NOTE_ACTIVITY.getMaxNote(), Math.round(notation.getNoteActivity() * 100.0) / 100.0); - String eco = String.format("%.2f/" + NotationNote.NOTE_PIB.getMaxNote(), Math.round(notation.getNoteEconomy() * 100.0) / 100.0); - String military = String.format("%.2f/" + NotationNote.NOTE_MILITARY.getMaxNote(), Math.round(notation.getNoteMilitary() * 100.0) / 100.0); + double noteActivity = notation.getNoteActivity() != null ? notation.getNoteActivity() : 0; + double noteEconomy = notation.getNoteEconomy() != null ? notation.getNoteEconomy() : 0; + double noteMilitary = notation.getNoteMilitary() != null ? notation.getNoteMilitary() : 0; + + String activity = String.format("%.2f/" + NotationNote.NOTE_ACTIVITY.getMaxNote(), Math.round(noteActivity * 100.0) / 100.0); + String eco = String.format("%.2f/" + NotationNote.NOTE_PIB.getMaxNote(), Math.round(noteEconomy * 100.0) / 100.0); + String military = String.format("%.2f/" + NotationNote.NOTE_MILITARY.getMaxNote(), Math.round(noteMilitary * 100.0) / 100.0); String arch = String.format("%.2f/" + NotationNote.NOTE_ARCHITECTURAL.getMaxNote(), Math.round(notation.getNoteArchitectural() * 100.0) / 100.0); String coh = String.format("%.2f/" + NotationNote.NOTE_COHERENCE.getMaxNote(), Math.round(notation.getNoteCoherence() * 100.0) / 100.0); String total = String.format("%.2f/%.0f", Math.round(notation.getTotalNote() * 100.0) / 100.0, NotationNote.getMaxTotalNote()); @@ -150,13 +154,18 @@ public static Component getHoverTotal(CityNotation notation) { return Component.text("Aucun total pour vous"); } + + double noteActivity = notation.getNoteActivity() != null ? notation.getNoteActivity() : 0; + double noteEconomy = notation.getNoteEconomy() != null ? notation.getNoteEconomy() : 0; + double noteMilitary = notation.getNoteMilitary() != null ? notation.getNoteMilitary() : 0; + return Component.text("§6§lDétails") .appendNewline() - .append(Component.text("§8Activité " + notation.getNoteActivity())) + .append(Component.text("§8Activité " + noteActivity)) .appendNewline() - .append(Component.text("§8Économie " + notation.getNoteEconomy())) + .append(Component.text("§8Économie " + noteEconomy)) .appendNewline() - .append(Component.text("§8Militaire " + notation.getNoteMilitary())) + .append(Component.text("§8Militaire " + noteMilitary)) .appendNewline() .append(Component.text("§8Architecture " + notation.getNoteArchitectural())) .appendNewline() From 295a8b54bbf1614eb7b87ea8c9910b884c96a24e Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sat, 14 Mar 2026 11:37:55 +0100 Subject: [PATCH 11/52] fix if milestone was finished (#1193) --- .../core/features/milestones/MilestonesManager.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java b/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java index 61f0c0ecc..fe9bc5672 100644 --- a/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java +++ b/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java @@ -86,7 +86,13 @@ public static void loadMilestonesProgress() { for (Milestone milestone : milestones) { // Pour tous les joueurs du milestone, la progression est chargée à l'étape actuelle for (Map.Entry playerData : milestone.getPlayerData().entrySet()) { - milestone.getSteps().get(playerData.getValue().getStep()).setProgress(playerData.getKey(), playerData.getValue().getProgress()); + int step = playerData.getValue().getStep(); + + if (step >= milestone.getSteps().size()) continue; + + milestone.getSteps() + .get(step) + .setProgress(playerData.getKey(), playerData.getValue().getProgress()); } } } From 96be457541d9e1e8d5b51c488ecef61d7fd59bd4 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Tue, 17 Mar 2026 20:19:02 +0100 Subject: [PATCH 12/52] Update target path for OpenMC.jar in workflow --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 59b52640f..fce443fc8 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -64,4 +64,4 @@ jobs: api-key: ${{ secrets.API_KEY }} server-id: ${{ secrets.SERVER_ID }} source: builds/OpenMC.jar - target: "./plugins/OpenMC.jar" + target: "./plugins/update/OpenMC.jar" From 07e2e5ec1668567db4c0facebfc0b5795f4fe126 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Tue, 17 Mar 2026 20:32:16 +0100 Subject: [PATCH 13/52] Update pterodactyl-upload-action to version 2.5 --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index fce443fc8..020728002 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -58,7 +58,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} - name: Deploy to server - uses: rexlmanu/pterodactyl-upload-action@v2.4 + uses: rexlmanu/pterodactyl-upload-action@v2.5 with: panel-host: ${{ secrets.PANEL_HOST }} api-key: ${{ secrets.API_KEY }} From eca02395f6563cf2b3927b9dc480c94581922780 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Tue, 17 Mar 2026 20:37:50 +0100 Subject: [PATCH 14/52] Add command to restart OpenMC after deployment --- .github/workflows/milestone-close.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 020728002..c10aef722 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -65,3 +65,4 @@ jobs: server-id: ${{ secrets.SERVER_ID }} source: builds/OpenMC.jar target: "./plugins/update/OpenMC.jar" + command: "omcrestart" From 54ce73e49d60e7cb0b7d7eff35bbf7039b03ead9 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Tue, 17 Mar 2026 21:26:21 +0100 Subject: [PATCH 15/52] Update source path for OpenMC.jar in workflow --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index c10aef722..b4239c18b 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -63,6 +63,6 @@ jobs: panel-host: ${{ secrets.PANEL_HOST }} api-key: ${{ secrets.API_KEY }} server-id: ${{ secrets.SERVER_ID }} - source: builds/OpenMC.jar + source: OpenMC.jar target: "./plugins/update/OpenMC.jar" command: "omcrestart" From bb7c8164692c4bc8f57a3130db640d7620dfa6eb Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 13:15:20 +0100 Subject: [PATCH 16/52] Ajout d'une commande /debug animation resetHead (#1199) * add debug animation resetHead * fix perm --- .../java/fr/openmc/core/CommandsManager.java | 4 +++- .../animations/DebugAnimationCommand.java | 17 +++++++++++++++++ .../animations/listeners/EmoteListener.java | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 src/main/java/fr/openmc/core/features/animations/DebugAnimationCommand.java diff --git a/src/main/java/fr/openmc/core/CommandsManager.java b/src/main/java/fr/openmc/core/CommandsManager.java index dad54dcc6..b37c8dc49 100644 --- a/src/main/java/fr/openmc/core/CommandsManager.java +++ b/src/main/java/fr/openmc/core/CommandsManager.java @@ -8,6 +8,7 @@ import fr.openmc.core.commands.fun.Playtime; import fr.openmc.core.commands.utils.*; import fr.openmc.core.features.adminshop.AdminShopCommand; +import fr.openmc.core.features.animations.DebugAnimationCommand; import fr.openmc.core.features.credits.CreditsCommand; import fr.openmc.core.features.cube.CubeCommands; import fr.openmc.core.features.events.halloween.commands.HalloweenCommands; @@ -59,7 +60,8 @@ private static void registerCommands() { new Cooldowns(), new CreditsCommand(), new CubeCommands(), - new HalloweenCommands() + new HalloweenCommands(), + new DebugAnimationCommand() ); } } diff --git a/src/main/java/fr/openmc/core/features/animations/DebugAnimationCommand.java b/src/main/java/fr/openmc/core/features/animations/DebugAnimationCommand.java new file mode 100644 index 000000000..820de0d44 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/animations/DebugAnimationCommand.java @@ -0,0 +1,17 @@ +package fr.openmc.core.features.animations; + +import fr.openmc.core.features.adminshop.AdminShopManager; +import fr.openmc.core.features.animations.listeners.EmoteListener; +import org.bukkit.entity.Player; +import revxrsal.commands.annotation.Command; +import revxrsal.commands.annotation.Description; +import revxrsal.commands.bukkit.annotation.CommandPermission; + + +public class DebugAnimationCommand { + @Command("debug animation resetHead") + @CommandPermission("omc.debug.animation.resetHead") + public void resetHead(Player player) { + EmoteListener.sendCamera(player, player); + } +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/features/animations/listeners/EmoteListener.java b/src/main/java/fr/openmc/core/features/animations/listeners/EmoteListener.java index add12cedf..acfc15fca 100644 --- a/src/main/java/fr/openmc/core/features/animations/listeners/EmoteListener.java +++ b/src/main/java/fr/openmc/core/features/animations/listeners/EmoteListener.java @@ -112,7 +112,7 @@ private void animationEnd(Player player) { * @param player The player to send the packet to. * @param entity The entity to set the camera to. */ - private void sendCamera(Player player, Entity entity) { + public static void sendCamera(Player player, Entity entity) { PacketContainer packet = new PacketContainer(PacketType.Play.Server.CAMERA); packet.getIntegers().write(0, entity.getEntityId()); ProtocolLibrary.getProtocolManager().sendServerPacket(player, packet); From ab98803d682d4d1b2853ede8740fa6b642658efe Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 16:00:00 +0100 Subject: [PATCH 17/52] Update action-gh-release to version 2.6.1 --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index b4239c18b..11fe22c6a 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -42,7 +42,7 @@ jobs: path: builds/ - name: Create GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@v2.6.1 with: tag_name: ${{ github.event.milestone.title }} name: Release milestone ${{ github.event.milestone.title }} From d8f2db2a548b97b33472c5d131f0021996c89070 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 16:37:57 +0100 Subject: [PATCH 18/52] Update GitHub Release action version --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 11fe22c6a..c882091fd 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -42,7 +42,7 @@ jobs: path: builds/ - name: Create GitHub Release - uses: softprops/action-gh-release@v2.6.1 + uses: ospfranco/action-gh-release@2.3.4 with: tag_name: ${{ github.event.milestone.title }} name: Release milestone ${{ github.event.milestone.title }} From 29a6a7c3d747c2592dc771ed78f5422f27855694 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:10:51 +0100 Subject: [PATCH 19/52] Add permissions for milestone close workflow --- .github/workflows/milestone-close.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index c882091fd..8d3ca2b80 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -4,6 +4,9 @@ on: milestone: types: [closed] +permissions: + contents: write + jobs: build-release: name: Release From 56cd148b25b9da73d26b40a151165a4efdcf1c71 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:14:03 +0100 Subject: [PATCH 20/52] Update action-gh-release to softprops version --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 8d3ca2b80..384a738f8 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -45,7 +45,7 @@ jobs: path: builds/ - name: Create GitHub Release - uses: ospfranco/action-gh-release@2.3.4 + uses: softprops/action-gh-release@v2.6.1 with: tag_name: ${{ github.event.milestone.title }} name: Release milestone ${{ github.event.milestone.title }} From c7801f7386afa5e1676a3327e94228e9e73c39a3 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:31:57 +0100 Subject: [PATCH 21/52] Fix release to discord --- .github/workflows/release-to-discord.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-to-discord.yml b/.github/workflows/release-to-discord.yml index d2f82f1ac..ebf417bfb 100644 --- a/.github/workflows/release-to-discord.yml +++ b/.github/workflows/release-to-discord.yml @@ -1,7 +1,9 @@ name: Release to Discord on: - release: - types: [published] + workflow_run: + workflows: [Handle closing a milestone] + types: + - completed jobs: github-releases-to-discord: From bd7f51c83018ec77b447bc66b20dbd07c6e4ae87 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:36:30 +0100 Subject: [PATCH 22/52] Fix command formatting in milestone-close.yml --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 384a738f8..80dbf0953 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -68,4 +68,4 @@ jobs: server-id: ${{ secrets.SERVER_ID }} source: OpenMC.jar target: "./plugins/update/OpenMC.jar" - command: "omcrestart" + command: omcrestart From 828809bb580aee1cccd740b91ce08bae2a57ef0b Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:47:28 +0100 Subject: [PATCH 23/52] Update GitHub Releases to Discord action version --- .github/workflows/release-to-discord.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-to-discord.yml b/.github/workflows/release-to-discord.yml index ebf417bfb..7b8f05f3e 100644 --- a/.github/workflows/release-to-discord.yml +++ b/.github/workflows/release-to-discord.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Github Releases To Discord - uses: SethCohen/github-releases-to-discord@v1.16.2 + uses: SethCohen/github-releases-to-discord@v1.19.0 with: webhook_url: ${{ secrets.WEBHOOK_URL }} color: "16021398" # decimal of #f47796 From 7a420b7548bad7c409ee699c37de627bef52cb4e Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:54:07 +0100 Subject: [PATCH 24/52] Revert fix release to discord --- .github/workflows/release-to-discord.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release-to-discord.yml b/.github/workflows/release-to-discord.yml index 7b8f05f3e..915020d91 100644 --- a/.github/workflows/release-to-discord.yml +++ b/.github/workflows/release-to-discord.yml @@ -1,9 +1,7 @@ name: Release to Discord on: - workflow_run: - workflows: [Handle closing a milestone] - types: - - completed + release: + types: [published] jobs: github-releases-to-discord: From acf6c290d643518f546caea74dbb5d78b1bc5489 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 17:58:34 +0100 Subject: [PATCH 25/52] Revert write permissions for contents in workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cela casse le systeme de detection de release publiée --- .github/workflows/milestone-close.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 80dbf0953..0d284f723 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -4,9 +4,6 @@ on: milestone: types: [closed] -permissions: - contents: write - jobs: build-release: name: Release From 6e5dfeffb97019a14060c05cac31343766acc1fc Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:06:40 +0100 Subject: [PATCH 26/52] Update action-gh-release to version 2 --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 0d284f723..c6248ed9f 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -42,7 +42,7 @@ jobs: path: builds/ - name: Create GitHub Release - uses: softprops/action-gh-release@v2.6.1 + uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.event.milestone.title }} name: Release milestone ${{ github.event.milestone.title }} From 6f25ebfc850703fff50f0f3641c8d0f8f662cff1 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:46:06 +0100 Subject: [PATCH 27/52] test if attribute need more perm --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index c6248ed9f..56666ec45 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -46,7 +46,7 @@ jobs: with: tag_name: ${{ github.event.milestone.title }} name: Release milestone ${{ github.event.milestone.title }} - generate_release_notes: true + generate_release_notes: false fail_on_unmatched_files: true make_latest: true body: | From ab314908c308c2e1f8543fae34fbaf54839cbd42 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:48:38 +0100 Subject: [PATCH 28/52] Enable release notes generation for milestones --- .github/workflows/milestone-close.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 56666ec45..c6248ed9f 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -46,7 +46,7 @@ jobs: with: tag_name: ${{ github.event.milestone.title }} name: Release milestone ${{ github.event.milestone.title }} - generate_release_notes: false + generate_release_notes: true fail_on_unmatched_files: true make_latest: true body: | From e82767d647c227e246f0605245ca11e05b02a424 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 18:51:16 +0100 Subject: [PATCH 29/52] final fix? Added RELEASE_TOKEN to GitHub Release step for authentication. --- .github/workflows/milestone-close.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index c6248ed9f..89cc85c9d 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -44,6 +44,7 @@ jobs: - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: + token: ${{ secrets.RELEASE_TOKEN }} tag_name: ${{ github.event.milestone.title }} name: Release milestone ${{ github.event.milestone.title }} generate_release_notes: true @@ -54,8 +55,6 @@ jobs: ${{ github.event.milestone.description }} files: builds/** - env: - GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} - name: Deploy to server uses: rexlmanu/pterodactyl-upload-action@v2.5 From b0fe724fd1c39cdb2ee8b5081e7ad8a6ca76adc5 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 19:05:23 +0100 Subject: [PATCH 30/52] Downgrade github-releases-to-discord version --- .github/workflows/release-to-discord.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-to-discord.yml b/.github/workflows/release-to-discord.yml index 915020d91..d2f82f1ac 100644 --- a/.github/workflows/release-to-discord.yml +++ b/.github/workflows/release-to-discord.yml @@ -11,7 +11,7 @@ jobs: - name: Checkout uses: actions/checkout@v4 - name: Github Releases To Discord - uses: SethCohen/github-releases-to-discord@v1.19.0 + uses: SethCohen/github-releases-to-discord@v1.16.2 with: webhook_url: ${{ secrets.WEBHOOK_URL }} color: "16021398" # decimal of #f47796 From f68064488f10e51ac277c85ee41af53250b7c4bc Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 19:40:11 +0100 Subject: [PATCH 31/52] Update release types format in workflow file --- .github/workflows/release-to-discord.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-to-discord.yml b/.github/workflows/release-to-discord.yml index d2f82f1ac..1f8677886 100644 --- a/.github/workflows/release-to-discord.yml +++ b/.github/workflows/release-to-discord.yml @@ -1,7 +1,7 @@ name: Release to Discord on: release: - types: [published] + types: ["published"] jobs: github-releases-to-discord: From db62cb2926907f1ef679bc26f8b79b7c1610505c Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 19:43:48 +0100 Subject: [PATCH 32/52] Fix YAML syntax for release types in workflow --- .github/workflows/release-to-discord.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-to-discord.yml b/.github/workflows/release-to-discord.yml index 1f8677886..d2f82f1ac 100644 --- a/.github/workflows/release-to-discord.yml +++ b/.github/workflows/release-to-discord.yml @@ -1,7 +1,7 @@ name: Release to Discord on: release: - types: ["published"] + types: [published] jobs: github-releases-to-discord: From 059017c8952d0ffd1c7c6c9b20f76302149f078e Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 19:45:55 +0100 Subject: [PATCH 33/52] Remove command from milestone-close workflow Removed the 'command' line from the workflow configuration. --- .github/workflows/milestone-close.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 89cc85c9d..a153a66bc 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -64,4 +64,3 @@ jobs: server-id: ${{ secrets.SERVER_ID }} source: OpenMC.jar target: "./plugins/update/OpenMC.jar" - command: omcrestart From 09d4552e24219f1ed7736fe2c94487a2979e7e3d Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 19:49:26 +0100 Subject: [PATCH 34/52] =?UTF-8?q?Rewrite=20de=20la=20base=20des=20boss=20b?= =?UTF-8?q?ars=20+=20impl=C3=A9mentation=20boss=20bar=20dans=20milestones?= =?UTF-8?q?=20(#1159)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: content is null * fix: fancy nps plugins not found * fix: fix cannot invoke "String.isEmpty()" because "content" is null * chore: BossbarManager.java + impl: bossbar in milestone * Update src/main/java/fr/openmc/core/features/displays/bossbar/BossbarManager.java Co-authored-by: PuppyTransGirl <74014559+PuppyTransGirl@users.noreply.github.com> --------- Co-authored-by: PuppyTransGirl <74014559+PuppyTransGirl@users.noreply.github.com> --- .../java/fr/openmc/core/ListenersManager.java | 2 - src/main/java/fr/openmc/core/OMCPlugin.java | 2 + .../displays/bossbar/BaseBossbar.java | 57 +++ .../displays/bossbar/BossbarManager.java | 344 +++++++----------- .../bossbar/commands/BossBarCommand.java | 138 +------ .../bossbar/contents/HelpConfigManager.java | 67 ++++ .../bossbar/contents/MainBossbar.java | 51 +++ .../bossbar/listeners/BossbarListener.java | 23 -- .../features/dream/displays/DreamBossBar.java | 76 ++-- .../dream/PlayerChangeWorldListener.java | 14 - .../listeners/dream/PlayerJoinListener.java | 8 - .../features/dream/models/db/DreamPlayer.java | 3 - .../core/features/milestones/Milestone.java | 46 ++- .../features/milestones/MilestoneQuest.java | 6 +- .../features/milestones/MilestoneStep.java | 6 + .../features/milestones/MilestoneType.java | 9 +- .../features/milestones/MilestoneUtils.java | 48 +-- .../milestones/MilestonesManager.java | 34 +- .../milestones/bossbar/MilestoneBossBar.java | 85 +++++ .../bossbar/MilestoneBossBarOptions.java | 5 + .../milestones/tutorial/TutorialBossBar.java | 54 --- .../tutorial/TutorialMilestone.java | 26 +- .../milestones/tutorial/TutorialStep.java | 3 +- .../listeners/TutorialBossBarEvent.java | 25 -- .../tutorial/quests/BreakAyweniteQuest.java | 17 +- 25 files changed, 535 insertions(+), 614 deletions(-) create mode 100644 src/main/java/fr/openmc/core/features/displays/bossbar/BaseBossbar.java create mode 100644 src/main/java/fr/openmc/core/features/displays/bossbar/contents/HelpConfigManager.java create mode 100644 src/main/java/fr/openmc/core/features/displays/bossbar/contents/MainBossbar.java delete mode 100644 src/main/java/fr/openmc/core/features/displays/bossbar/listeners/BossbarListener.java create mode 100644 src/main/java/fr/openmc/core/features/milestones/MilestoneStep.java create mode 100644 src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBar.java create mode 100644 src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBarOptions.java delete mode 100644 src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialBossBar.java delete mode 100644 src/main/java/fr/openmc/core/features/milestones/tutorial/listeners/TutorialBossBarEvent.java diff --git a/src/main/java/fr/openmc/core/ListenersManager.java b/src/main/java/fr/openmc/core/ListenersManager.java index c4a5a44d1..1ea12e498 100644 --- a/src/main/java/fr/openmc/core/ListenersManager.java +++ b/src/main/java/fr/openmc/core/ListenersManager.java @@ -5,7 +5,6 @@ import fr.openmc.core.features.cube.listeners.CubeListener; import fr.openmc.core.features.cube.listeners.RepulseEffectListener; import fr.openmc.core.features.cube.multiblocks.MultiBlocksListeners; -import fr.openmc.core.features.displays.bossbar.listeners.BossbarListener; import fr.openmc.core.features.itemsadder.SpawnerExtractorListener; import fr.openmc.core.features.settings.PlayerSettingsManager; import fr.openmc.core.features.tickets.TicketListener; @@ -34,7 +33,6 @@ public static void init() { new SleepListener(), new PlayerDeathListener(), new AsyncChatListener(OMCPlugin.getInstance()), - new BossbarListener(), new PlayerSettingsManager(), new InteractListener(), new EquipableItemListener(), diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index 3518e9882..ac1fbb50c 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -19,6 +19,7 @@ import fr.openmc.core.features.cube.multiblocks.MultiBlockManager; import fr.openmc.core.features.displays.TabList; import fr.openmc.core.features.displays.bossbar.BossbarManager; +import fr.openmc.core.features.displays.bossbar.contents.HelpConfigManager; import fr.openmc.core.features.displays.holograms.HologramLoader; import fr.openmc.core.features.displays.scoreboards.ScoreboardManager; import fr.openmc.core.features.dream.DreamManager; @@ -134,6 +135,7 @@ public void onEnable() { QuestProgressSaveManager.init(); TabList.init(); AdminShopManager.init(); + HelpConfigManager.init(); BossbarManager.init(); AnimationsManager.init(); HalloweenManager.init(); diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/BaseBossbar.java b/src/main/java/fr/openmc/core/features/displays/bossbar/BaseBossbar.java new file mode 100644 index 000000000..8f4ef79d3 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/displays/bossbar/BaseBossbar.java @@ -0,0 +1,57 @@ +package fr.openmc.core.features.displays.bossbar; + +import net.kyori.adventure.bossbar.BossBar; +import org.bukkit.boss.BarColor; +import org.bukkit.entity.Player; + +public abstract class BaseBossbar { + /** + * Initialise la boss bar pour un joueur + * + * @param player Le joueur + */ + public void init(Player player, BossBar bar) { + update(player, bar); + } + + protected abstract String id(); + + /** + * Met à jour la boss bar + * + * @param player Le joueur + */ + protected abstract void update(Player player, BossBar bar); + + /** + * Détermine la couleur de la boss bar + * @param player Le joueur + * @return La couleur de la boss bar + */ + protected abstract BossBar.Color color(Player player); + + /** + * Détermine le style de la boss bar + * @param player Le joueur + * @return Le style de la boss bar + */ + protected abstract BossBar.Overlay style(Player player); + + /** + * Détermine si le boss bar doit être affiché pour un joueur + * + * @param player Le joueur à vérifier + * @return true si la boss bar doit être affiché, false sinon + */ + protected abstract boolean shouldDisplay(Player player); + + /** + * @return Le poids de la boss bar (plus la valeur est haute, plus la position de la boss bar sera haute). + */ + protected abstract int weight(); + + /** + * @return L'intervalle de mise à jour en secondes + */ + protected abstract Integer updateInterval(); +} diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/BossbarManager.java b/src/main/java/fr/openmc/core/features/displays/bossbar/BossbarManager.java index 1c1b003fd..f6b30bc53 100644 --- a/src/main/java/fr/openmc/core/features/displays/bossbar/BossbarManager.java +++ b/src/main/java/fr/openmc/core/features/displays/bossbar/BossbarManager.java @@ -3,10 +3,9 @@ import fr.openmc.core.CommandsManager; import fr.openmc.core.OMCPlugin; import fr.openmc.core.features.displays.bossbar.commands.BossBarCommand; -import fr.openmc.core.features.milestones.MilestoneUtils; -import fr.openmc.core.utils.messages.MessageType; -import fr.openmc.core.utils.messages.MessagesManager; -import fr.openmc.core.utils.messages.Prefix; +import fr.openmc.core.features.displays.bossbar.contents.MainBossbar; +import fr.openmc.core.features.displays.scoreboards.BaseScoreboard; +import fr.openmc.core.features.dream.displays.DreamBossBar; import lombok.Getter; import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; @@ -20,267 +19,174 @@ import java.util.*; public class BossbarManager { - @Getter - private static final List helpMessages = new ArrayList<>(); - private static final HashMap> activeBossBars = new HashMap<>(); - private static final Map playerPreferences = new HashMap<>(); - @Getter - private static boolean bossBarEnabled = true; - @Getter - private static File configFile; - private static int currentMessageIndex = 0; - - public static BossBar bossBarHelp; - - /** - * Initializes the BossbarManager - */ + private static final List registeredBossbar = new ArrayList<>(); + + private static final Map> activeBossbars = new HashMap<>(); + private static final Map> lastUpdate = new HashMap<>(); + private static final Map> offBossbars = new HashMap<>(); + public static void init() { - configFile = new File(OMCPlugin.getInstance().getDataFolder() + "/data", "bossbars.yml"); - loadConfig(); - loadDefaultMessages(); - startRotationTask(); CommandsManager.getHandler().register(new BossBarCommand()); - bossBarHelp = BossBar.bossBar( - helpMessages.getFirst(), - 0f, - BossBar.Color.RED, - BossBar.Overlay.PROGRESS + registerBossbars( + new MainBossbar(), + new DreamBossBar() ); - } - /** - * Loads configuration from bossbars.yml file - * Creates the file if it doesn't exist - */ - private static void loadConfig() { - if (!configFile.exists()) { - configFile.getParentFile().mkdirs(); - OMCPlugin.getInstance().saveResource("data/bossbars.yml", false); - } - reloadMessages(); + start(); } - /** - * Loads messages from the configuration file - */ - private static void loadDefaultMessages() { - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - helpMessages.clear(); - - for (String rawMessage : config.getStringList("messages")) { - helpMessages.add(MiniMessage.miniMessage().deserialize(rawMessage)); - } - - if (helpMessages.isEmpty()) { - OMCPlugin.getInstance().getSLF4JLogger().warn("No messages found in bossbars.yml."); - } + public static void registerBossbars(BaseBossbar... bossbar) { + registeredBossbar.addAll(Arrays.asList(bossbar)); + registeredBossbar.sort(Comparator.comparingInt(BaseBossbar::weight).reversed()); } - /** - * Starts the message rotation task for bossbars - * Messages change every 10 seconds (200 ticks) - */ - private static void startRotationTask() { + private static void start() { new BukkitRunnable() { @Override public void run() { - if (helpMessages.isEmpty()) return; + for (Player player : Bukkit.getOnlinePlayers()) { + updatePlayer(player); + } + } + }.runTaskTimer(OMCPlugin.getInstance(), 0L, 20L); + } + - currentMessageIndex = (currentMessageIndex + 1) % helpMessages.size(); - Component message = helpMessages.get(currentMessageIndex); + private static void updatePlayer(Player player) { - activeBossBars.forEach((type, bossBarData) -> { - if (!type.equals(BossbarsType.HELP)) return; + UUID uuid = player.getUniqueId(); + + activeBossbars.putIfAbsent(uuid, new HashMap<>()); + offBossbars.putIfAbsent(uuid, new HashSet<>()); + lastUpdate.putIfAbsent(uuid, new HashMap<>()); + + Map playerBars = activeBossbars.get(uuid); + Set toggled = offBossbars.get(uuid); + Map playerLastUpdate = lastUpdate.get(uuid); - bossBarData.forEach((uuid, bossBar) -> { - if (bossBar != null) { - bossBar.name(message); - } - }); - }); + long now = System.currentTimeMillis(); + + for (BaseBossbar base : registeredBossbar) { + String id = base.id(); + + if (toggled.contains(id)) { + removeBossBar(player, id); + continue; } - }.runTaskTimer(OMCPlugin.getInstance(), 0, 200); - } - /** - * Adds a bossbar to the specified player - * @param type The type of bossbar to add - * @param bossbar The bossbar to add - * @param player The player to add the bossbar to - */ - public static void addBossBar(BossbarsType type, BossBar bossbar, Player player) { - if (!bossBarEnabled) return; - - Map bars = activeBossBars.get(type); - if (bars != null && bars.containsKey(player.getUniqueId())) return; - - Boolean preference = playerPreferences.get(player.getUniqueId()); - if (preference != null && !preference) { - return; - } - removeBossBar(type, player); + boolean shouldDisplay = base.shouldDisplay(player); + BossBar existing = playerBars.get(id); - player.showBossBar(bossbar); - activeBossBars.computeIfAbsent(type, k -> new HashMap<>()).put(player.getUniqueId(), bossbar); - } + if (shouldDisplay) { - /** - * Removes the bossbar from the specified player - * @param type The type of bossbar to remove - * @param player The player to remove the bossbar from - */ - public static void removeBossBar(BossbarsType type, Player player) { - Map map = activeBossBars.get(type); - if (map == null) return; - - BossBar bossBar = map.remove(player.getUniqueId()); - if (bossBar != null) { - player.hideBossBar(bossBar); - } - } + if (existing == null) { + existing = BossBar.bossBar( + Component.text(), + 1f, + base.color(player), + base.style(player) + ); - /** - * Gets the bossbar for a specific player - * - * @param type The type of bossbar to get - * @param player The player to get the bossbar for - * @return The bossbar for the specified player, or null if not found - */ - public static BossBar getBossBar(BossbarsType type, Player player) { - if (activeBossBars.get(type) == null) return null; + player.showBossBar(existing); + playerBars.put(id, existing); - return activeBossBars.get(type).get(player.getUniqueId()); + base.update(player, existing); + playerLastUpdate.put(id, now); + continue; + } - } + long last = playerLastUpdate.getOrDefault(id, 0L); + long intervalMillis = base.updateInterval() * 1000L; - /** - * Toggles the bossbar for a specific player - * @param player The player to toggle the bossbar for - */ - public static void toggleBossBar(Player player) { - UUID uuid = player.getUniqueId(); - boolean enabled = false; - - for (Map.Entry> activeBossBar : activeBossBars.entrySet()) { - BossbarsType type = activeBossBar.getKey(); - Map bossBarData = activeBossBar.getValue(); - if (bossBarData.containsKey(uuid)) { - removeBossBar(type, player); - enabled = false; - playerPreferences.put(uuid, false); - } else { - switch (type) { - case HELP -> { - addBossBar(type, bossBarHelp, player); - enabled = true; - playerPreferences.put(uuid, true); - } - - case TUTORIAL -> { - MilestoneUtils.setBossBar(player); - enabled = true; - playerPreferences.put(uuid, true); - } + if (now - last >= intervalMillis) { + base.update(player, existing); + playerLastUpdate.put(id, now); } - } - } - if (enabled) { - MessagesManager.sendMessage(player, Component.text("Bossbar activée"), Prefix.OPENMC, MessageType.SUCCESS, true); - } else { - MessagesManager.sendMessage(player, Component.text("Bossbar désactivée"), Prefix.OPENMC, MessageType.WARNING, true); + } else { + removeBossBar(player, id); + playerLastUpdate.remove(id); + } } } - /** - * Reloads messages from the configuration file - */ - public static void reloadMessages() { - helpMessages.clear(); - loadDefaultMessages(); - } + public static void addBossBar(Player player, String id) { + BaseBossbar base = getRegistered(id); + if (base == null) return; - /** - * Checks if bossbars are globally enabled - * @return true if bossbars are enabled, false otherwise - */ - public static boolean hasBossBar() { - return bossBarEnabled; - } + activeBossbars.putIfAbsent(player.getUniqueId(), new HashMap<>()); - /** - * Sets the list of messages to display in bossbars - * @param messages The list of new messages - */ - public static void setHelpMessages(List messages) { - helpMessages.clear(); - helpMessages.addAll(messages); - saveMessagesToConfig(); + Map playerBars = activeBossbars.get(player.getUniqueId()); + + if (playerBars.containsKey(id)) return; + + BossBar bar = BossBar.bossBar( + Component.text(), + 1L, + base.color(player), + base.style(player) + ); + + player.showBossBar(bar); + playerBars.put(id, bar); } - /** - * Saves messages to the configuration file - */ - private static void saveMessagesToConfig() { - try { - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - List serializedMessages = new ArrayList<>(); + public static void removeBossBar(Player player, String id) { + Map bars = activeBossbars.get(player.getUniqueId()); + if (bars == null) return; - for (Component message : helpMessages) { - serializedMessages.add(MiniMessage.miniMessage().serialize(message)); - } + BossBar bar = bars.remove(id); - config.set("messages", serializedMessages); - config.save(configFile); - } catch (Exception e) { - OMCPlugin.getInstance().getSLF4JLogger().warn("Failed to save bossbar messages to config: {}", e.getMessage(), e); + if (bar != null) { + player.hideBossBar(bar); } } - /** - * Adds a message to the message list - * @param message The message to add - */ - public static void addMessage(Component message) { - helpMessages.add(message); - saveMessagesToConfig(); + public static BossBar getBossBar(Player player, String id) { + Map bars = activeBossbars.get(player.getUniqueId()); + if (bars == null) return null; + return bars.get(id); } - /** - * Removes a message from the message list - * @param index The index of the message to remove - */ - public static void removeMessage(int index) { - if (index >= 0 && index < helpMessages.size()) { - helpMessages.remove(index); - saveMessagesToConfig(); + public static void toggleBossBar(Player player, String id) { + offBossbars.putIfAbsent(player.getUniqueId(), new HashSet<>()); + + Set toggled = offBossbars.get(player.getUniqueId()); + + if (toggled.contains(id)) { + toggled.remove(id); + } else { + toggled.add(id); + removeBossBar(player, id); } } - /** - * Updates an existing message - * @param index The index of the message to update - * @param newMessage The new message content - */ - public static void updateMessage(int index, Component newMessage) { - if (index >= 0 && index < helpMessages.size()) { - helpMessages.set(index, newMessage); - saveMessagesToConfig(); + public static void toggleAllBossBar(Player player) { + for (BaseBossbar baseBossbar : registeredBossbar) { + toggleBossBar(player, baseBossbar.id()); } } - /** - * Toggles bossbars globally for all players - */ - public static void toggleGlobalBossBar() { - bossBarEnabled = !bossBarEnabled; + public static boolean isToggled(Player player, String id) { + return offBossbars.getOrDefault(player.getUniqueId(), Set.of()).contains(id); + } - if (bossBarEnabled) { - Bukkit.getOnlinePlayers().forEach(player -> addBossBar(BossbarsType.HELP, bossBarHelp, player)); - } else { - Bukkit.getOnlinePlayers().forEach(player -> removeBossBar(BossbarsType.HELP, player)); + public static void removePlayer(Player player) { + Map bars = activeBossbars.remove(player.getUniqueId()); + if (bars != null) { + for (BossBar bar : bars.values()) { + player.hideBossBar(bar); + } } + + offBossbars.remove(player.getUniqueId()); + } + + private static BaseBossbar getRegistered(String id) { + return registeredBossbar.stream() + .filter(b -> b.id().equalsIgnoreCase(id)) + .findFirst() + .orElse(null); } } diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/commands/BossBarCommand.java b/src/main/java/fr/openmc/core/features/displays/bossbar/commands/BossBarCommand.java index 7d81d9960..efb045e33 100644 --- a/src/main/java/fr/openmc/core/features/displays/bossbar/commands/BossBarCommand.java +++ b/src/main/java/fr/openmc/core/features/displays/bossbar/commands/BossBarCommand.java @@ -25,141 +25,7 @@ public class BossBarCommand { @CommandPlaceholder() - public void mainCommand(CommandSender sender) { - if (!(sender instanceof Player player)) { - MessagesManager.sendMessage(sender, MessagesManager.Message.NO_PERMISSION.getMessage(), Prefix.OPENMC, MessageType.ERROR, true); - return; - } - - BossbarManager.toggleBossBar(player); - } - - @CommandPermission("omc.admin.commands.bossbar.reload") - @Subcommand("reload") - public void reloadCommand(CommandSender sender) { - BossbarManager.reloadMessages(); - MessagesManager.sendMessage(sender, Component.text("§aBossbar rechargée avec succès !"), Prefix.OPENMC, MessageType.SUCCESS, true); - } - - @CommandPermission("omc.admin.commands.bossbar.toggle") - @Subcommand("toggle") - public void toggleCommand(CommandSender sender) { - BossbarManager.toggleGlobalBossBar(); - if (sender instanceof Player player) { - MessagesManager.sendMessage(player, Component.text("§aBossbar " + (BossbarManager.hasBossBar() ? "activée" : "désactivée") + " pour vous."), Prefix.OPENMC, MessageType.SUCCESS, true); - } - } - - @CommandPermission("omc.admin.commands.bossbar.manage") - @Subcommand("manage") - public void manageCommand(BukkitCommandActor actor) { - if (!(actor.sender() instanceof Player player)) { - return; - } - - List messages = BossbarManager.getHelpMessages(); - - Component header = Component.text("\n§6§lGestion des messages de la bossbar\n") - .color(NamedTextColor.GOLD) - .decorate(TextDecoration.BOLD); - - MessagesManager.sendMessage(player, header, Prefix.OPENMC, MessageType.NONE, false); - - Component addButton = Component.text("[Ajouter un message]") - .color(NamedTextColor.GREEN) - .clickEvent(ClickEvent.suggestCommand("/omcbossbar add ")) - .hoverEvent(HoverEvent.showText(Component.text("Cliquez pour ajouter un message"))); - - MessagesManager.sendMessage(player, addButton, Prefix.OPENMC, MessageType.NONE, false); - - for (int i = 0; i < messages.size(); i++) { - Component messageLine = Component.text((i + 1) + ". ", NamedTextColor.GRAY) - .append(messages.get(i)) - .append(Component.space()) - .append(createActionButton("✎ Éditer", "/omcbossbar edit " + i + " " + messages.get(i), NamedTextColor.YELLOW)) - .append(Component.space()) - .append(createActionButton("✖ Supprimer", "/omcbossbar confirm " + i, NamedTextColor.RED)); - - MessagesManager.sendMessage(player, messageLine, Prefix.OPENMC, MessageType.NONE, false); - } - - Component refreshButton = Component.text("\n[Rafraîchir]") - .color(NamedTextColor.BLUE) - .clickEvent(ClickEvent.runCommand("/omcbossbar manage")) - .hoverEvent(HoverEvent.showText(Component.text("Actualiser la liste"))); - - MessagesManager.sendMessage(player, refreshButton, Prefix.OPENMC, MessageType.NONE, false); - } - - private Component createActionButton(String text, String command, NamedTextColor color) { - return Component.text(text) - .color(color) - .clickEvent(ClickEvent.suggestCommand(command)) - .hoverEvent(HoverEvent.showText(Component.text("Exécuter : " + command))); - } - - @CommandPermission("omc.admin.commands.bossbar.manage") - @Subcommand("add") - public void addMessage( - BukkitCommandActor actor, - @Named("message") String message - ) { - try { - Component component = MiniMessage.miniMessage().deserialize(message); - BossbarManager.addMessage(component); - BossbarManager.reloadMessages(); - - MessagesManager.sendMessage(actor.sender(), Component.text("§aMessage ajouté avec succès !"), Prefix.OPENMC, MessageType.SUCCESS, true); - manageCommand(actor); - } catch (Exception e) { - MessagesManager.sendMessage(actor.sender(), Component.text("§cErreur lors de l'ajout du message ! Assurez-vous que le format est correct."), Prefix.OPENMC, MessageType.ERROR, true); - } - } - - @CommandPermission("omc.admin.commands.bossbar.manage") - @Subcommand("edit") - public void editMessage( - BukkitCommandActor actor, - @Named("index") int index, - @Named("message edité") String newMessage - ) { - try { - Component component = MiniMessage.miniMessage().deserialize(newMessage); - BossbarManager.updateMessage(index, component); - BossbarManager.reloadMessages(); - MessagesManager.sendMessage(actor.sender(), Component.text("§aMessage mis à jour avec succès !"), Prefix.OPENMC, MessageType.SUCCESS, true); - manageCommand(actor); - } catch (Exception e) { - MessagesManager.sendMessage(actor.sender(), Component.text("§cFormat de message ou index invalide !"), Prefix.OPENMC, MessageType.ERROR, true); - } - } - - @CommandPermission("omc.admin.commands.bossbar.manage") - @Subcommand("confirm") - public void confirmDelete( - BukkitCommandActor actor, - @Named("index") int index - ) { - Component confirmation = Component.text() - .append(Component.text("§eÊtes-vous sûr de vouloir supprimer ce message ?")) - .append(Component.text("[OUI]") - .color(NamedTextColor.RED) - .clickEvent(ClickEvent.runCommand("/omcbossbar delete " + index)) - .hoverEvent(HoverEvent.showText(Component.text("Confirmer la suppression")))) - .build(); - - actor.reply(confirmation); - } - - @CommandPermission("omc.admin.commands.bossbar.manage") - @Subcommand("delete") - public void deleteMessage( - BukkitCommandActor actor, - @Named("index") int index - ) { - BossbarManager.removeMessage(index); - BossbarManager.reloadMessages(); - MessagesManager.sendMessage(actor.sender(), Component.text("Message supprimé avec succès."), Prefix.OPENMC, MessageType.SUCCESS, true); - manageCommand(actor); + public void mainCommand(Player player) { + BossbarManager.toggleBossBar(player, "omc:help"); } } diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/contents/HelpConfigManager.java b/src/main/java/fr/openmc/core/features/displays/bossbar/contents/HelpConfigManager.java new file mode 100644 index 000000000..b4ea4d6b0 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/displays/bossbar/contents/HelpConfigManager.java @@ -0,0 +1,67 @@ +package fr.openmc.core.features.displays.bossbar.contents; + +import fr.openmc.core.CommandsManager; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.displays.bossbar.commands.BossBarCommand; +import lombok.Getter; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public class HelpConfigManager { + + @Getter + private static final List helpMessages = new ArrayList<>(); + @Getter + private static File configFile; + + /** + * Initializes the HelpConfigManager by loading the configuration and default messages + */ + public static void init() { + configFile = new File(OMCPlugin.getInstance().getDataFolder() + "/data", "bossbars.yml"); + loadConfig(); + loadDefaultMessages(); + } + + /** + * Loads configuration from bossbars.yml file + * Creates the file if it doesn't exist + */ + private static void loadConfig() { + if (!configFile.exists()) { + configFile.getParentFile().mkdirs(); + OMCPlugin.getInstance().saveResource("data/bossbars.yml", false); + } + reloadMessages(); + } + + /** + * Loads messages from the configuration file + */ + private static void loadDefaultMessages() { + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + helpMessages.clear(); + + for (String rawMessage : config.getStringList("messages")) { + helpMessages.add(MiniMessage.miniMessage().deserialize(rawMessage)); + } + + if (helpMessages.isEmpty()) { + OMCPlugin.getInstance().getSLF4JLogger().warn("No messages found in bossbars.yml."); + } + } + + /** + * Reloads messages from the configuration file + */ + public static void reloadMessages() { + helpMessages.clear(); + loadDefaultMessages(); + } +} diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/contents/MainBossbar.java b/src/main/java/fr/openmc/core/features/displays/bossbar/contents/MainBossbar.java new file mode 100644 index 000000000..f146dd2d7 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/displays/bossbar/contents/MainBossbar.java @@ -0,0 +1,51 @@ +package fr.openmc.core.features.displays.bossbar.contents; + +import fr.openmc.core.features.displays.bossbar.BaseBossbar; +import fr.openmc.core.features.dream.DreamUtils; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.entity.Player; + +import java.util.List; + +public class MainBossbar extends BaseBossbar { + + private static int indexMessage = 0; + + @Override + protected String id() { + return "omc:help"; + } + + @Override + protected void update(Player player, BossBar bar) { + indexMessage = (indexMessage + 1) % HelpConfigManager.getHelpMessages().size(); + + bar.name(HelpConfigManager.getHelpMessages().get(indexMessage)); + } + + @Override + protected BossBar.Color color(Player player) { + return BossBar.Color.RED; + } + + @Override + protected BossBar.Overlay style(Player player) { + return BossBar.Overlay.PROGRESS; + } + + @Override + protected boolean shouldDisplay(Player player) { + return !DreamUtils.isInDreamWorld(player); + } + + @Override + protected int weight() { + return 10; + } + + @Override + protected Integer updateInterval() { + return 20; + } +} diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/listeners/BossbarListener.java b/src/main/java/fr/openmc/core/features/displays/bossbar/listeners/BossbarListener.java deleted file mode 100644 index 45379736d..000000000 --- a/src/main/java/fr/openmc/core/features/displays/bossbar/listeners/BossbarListener.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.openmc.core.features.displays.bossbar.listeners; - -import fr.openmc.core.features.displays.bossbar.BossbarManager; -import fr.openmc.core.features.displays.bossbar.BossbarsType; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -import static fr.openmc.core.features.displays.bossbar.BossbarManager.bossBarHelp; - -public class BossbarListener implements Listener { - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - BossbarManager.addBossBar(BossbarsType.HELP, bossBarHelp, event.getPlayer()); - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - BossbarManager.removeBossBar(BossbarsType.HELP, event.getPlayer()); - } -} diff --git a/src/main/java/fr/openmc/core/features/dream/displays/DreamBossBar.java b/src/main/java/fr/openmc/core/features/dream/displays/DreamBossBar.java index cf3efd507..246591489 100644 --- a/src/main/java/fr/openmc/core/features/dream/displays/DreamBossBar.java +++ b/src/main/java/fr/openmc/core/features/dream/displays/DreamBossBar.java @@ -1,7 +1,11 @@ package fr.openmc.core.features.dream.displays; +import fr.openmc.core.features.displays.bossbar.BaseBossbar; import fr.openmc.core.features.displays.bossbar.BossbarManager; import fr.openmc.core.features.displays.bossbar.BossbarsType; +import fr.openmc.core.features.dream.DreamManager; +import fr.openmc.core.features.dream.DreamUtils; +import fr.openmc.core.features.dream.models.db.DreamPlayer; import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -11,45 +15,45 @@ * *

Cette classe permet d'ajouter, mettre à jour et cacher la BossBar associée à un joueur.

*/ -public class DreamBossBar { - - private static final Component TEXTURE_BOSSBAR = Component.text(""); - - /** - * Ajoute une BossBar pour le joueur spécifié dans la Dimension des Rêves. - * - * @param player le joueur auquel ajouter la BossBar - * @param progress la progression de la BossBar - */ - public static void addDreamBossBarForPlayer(Player player, float progress) { - BossBar bar = BossBar.bossBar( - TEXTURE_BOSSBAR, - progress, - BossBar.Color.BLUE, - BossBar.Overlay.PROGRESS - ); - BossbarManager.addBossBar(BossbarsType.DREAM, bar, player); +public class DreamBossBar extends BaseBossbar { + @Override + protected String id() { + return "omc:dream"; } - /** - * Met à jour la progression de la BossBar pour le joueur spécifié. - * - * @param player le joueur dont la BossBar doit être mise à jour - * @param progress la nouvelle progression de la BossBar - */ - public static void update(Player player, float progress) { - BossBar bar = BossbarManager.getBossBar(BossbarsType.DREAM, player); - if (bar != null) { - bar.progress(progress); - } + @Override + protected void update(Player player, BossBar bar) { + DreamPlayer dreamPlayer = DreamManager.getDreamPlayer(player); + + if (dreamPlayer == null) return; + + float progress = Math.min(1, (float) dreamPlayer.getDreamTime() / dreamPlayer.getMaxDreamTime()); + + bar.progress(progress); + } + + @Override + protected BossBar.Color color(Player player) { + return BossBar.Color.BLUE; + } + + @Override + protected BossBar.Overlay style(Player player) { + return BossBar.Overlay.PROGRESS; + } + + @Override + protected boolean shouldDisplay(Player player) { + return DreamUtils.isInDreamWorld(player); + } + + @Override + protected int weight() { + return 10; } - /** - * Cache (supprime) la BossBar du joueur spécifié. - * - * @param player le joueur dont la BossBar doit être supprimée - */ - public static void hide(Player player) { - BossbarManager.removeBossBar(BossbarsType.DREAM, player); + @Override + protected Integer updateInterval() { + return 1; } } diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerChangeWorldListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerChangeWorldListener.java index 84ba003f7..dd7393748 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerChangeWorldListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerChangeWorldListener.java @@ -24,10 +24,6 @@ public void onDreamEntrered(PlayerTeleportEvent event) { if (!DreamUtils.isDreamWorld(event.getTo())) return; if (DreamUtils.isDreamWorld(event.getFrom())) return; - for (BossbarsType type : BossbarsType.values()) { - BossbarManager.removeBossBar(type, player); - } - try { DreamManager.addDreamPlayer(player, event.getFrom()); } catch (IOException e) { @@ -37,8 +33,6 @@ public void onDreamEntrered(PlayerTeleportEvent event) { DreamPlayer dreamPlayer = DreamManager.getDreamPlayer(player); if (dreamPlayer == null) return; - DreamBossBar.addDreamBossBarForPlayer(player, Math.min(1, (float) dreamPlayer.getDreamTime() / dreamPlayer.getMaxDreamTime())); - player.setFoodLevel(20); player.setSaturation(10.0f); AttributeInstance inst = player.getAttribute(Attribute.MAX_HEALTH); @@ -53,14 +47,6 @@ public void onDreamLeave(PlayerTeleportEvent event) { if (!DreamUtils.isDreamWorld(event.getFrom())) return; if (DreamUtils.isDreamWorld(event.getTo())) return; - for (BossbarsType type : BossbarsType.values()) { - if (type.equals(BossbarsType.DREAM)) continue; - - BossbarManager.addBossBar(type, BossbarManager.bossBarHelp, player); - } - - BossbarManager.removeBossBar(BossbarsType.DREAM, player); - DreamManager.removeDreamPlayer(player, event.getFrom()); } } diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerJoinListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerJoinListener.java index f507cec39..80ada5d61 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerJoinListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerJoinListener.java @@ -23,14 +23,6 @@ public void onPlayerJoinInDream(PlayerJoinEvent event) { if (!DreamUtils.isInDreamWorld(player)) return; - for (BossbarsType type : BossbarsType.values()) { - if (type.equals(BossbarsType.DREAM)) continue; - - BossbarManager.addBossBar(type, BossbarManager.bossBarHelp, player); - } - - BossbarManager.removeBossBar(BossbarsType.DREAM, player); - try { DreamManager.preloadSavePlayer(player, player.getLocation()); } catch (IOException e) { diff --git a/src/main/java/fr/openmc/core/features/dream/models/db/DreamPlayer.java b/src/main/java/fr/openmc/core/features/dream/models/db/DreamPlayer.java index 530c48d22..65fe90834 100644 --- a/src/main/java/fr/openmc/core/features/dream/models/db/DreamPlayer.java +++ b/src/main/java/fr/openmc/core/features/dream/models/db/DreamPlayer.java @@ -98,10 +98,7 @@ public void scheduleTimeTask() { Bukkit.getServer().getPluginManager().callEvent(new DreamEndEvent(this.player)) ); this.cancelTimeTask(); - return; } - - DreamBossBar.update(player, Math.min(1, (float) this.getDreamTime() / this.getMaxDreamTime())); }, 0L, 20L); } diff --git a/src/main/java/fr/openmc/core/features/milestones/Milestone.java b/src/main/java/fr/openmc/core/features/milestones/Milestone.java index 8358b023b..6052e510c 100644 --- a/src/main/java/fr/openmc/core/features/milestones/Milestone.java +++ b/src/main/java/fr/openmc/core/features/milestones/Milestone.java @@ -1,15 +1,18 @@ package fr.openmc.core.features.milestones; import fr.openmc.api.menulib.Menu; +import fr.openmc.core.features.milestones.bossbar.MilestoneBossBarOptions; +import fr.openmc.core.features.milestones.tutorial.TutorialStep; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.UUID; -public interface Milestone { +public interface Milestone & MilestoneStep> { HashMap playerData = new HashMap<>(); /** @@ -42,13 +45,18 @@ default HashMap getPlayerData() { * @return The icon of the milestone. */ ItemStack getIcon(); - + /** - * Returns the steps of the milestone. - * - * @return A step list of the milestone. + * @return The class of the steps for the milestone. + */ + Class getStepClass(); + + /** + * @return The enum constants of the step class for the milestone. */ - List getSteps(); + default T[] getStepEnum() { + return this.getStepClass().getEnumConstants(); + } /** * Returns the Type of the Milestone @@ -64,4 +72,30 @@ default HashMap getPlayerData() { * @return The menu for the milestone. */ Menu getMenu(Player player); + + /** + * Returns the boss bar options for the milestone. + * If set to null, no boss bar will be displayed for the milestone. + * + * @return The boss bar options for the milestone. + */ + MilestoneBossBarOptions getBossBarOptions(); + + /** + * Determines whether the boss bar should be displayed for the given player. + * + * @param player The player for whom to check if the boss bar should be displayed. + * @return true if the boss bar should be displayed for the player, false otherwise. + */ + boolean shouldDisplayBossBar(Player player); + /** + * Returns the steps of the milestone. + * + * @return A step list of the milestone. + */ + default List getSteps() { + T[] enumStep = this.getStepEnum(); + return Arrays.stream(enumStep).map(MilestoneStep::getQuest).toList(); + } + } diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestoneQuest.java b/src/main/java/fr/openmc/core/features/milestones/MilestoneQuest.java index fed40f108..f72576d79 100644 --- a/src/main/java/fr/openmc/core/features/milestones/MilestoneQuest.java +++ b/src/main/java/fr/openmc/core/features/milestones/MilestoneQuest.java @@ -13,9 +13,9 @@ public class MilestoneQuest extends Quest { protected final MilestoneType type; - protected final Enum step; + protected final Enum step; - public MilestoneQuest(String name, List baseDescription, Material icon, MilestoneType type, Enum step, QuestTier quest) { + public MilestoneQuest(String name, List baseDescription, Material icon, MilestoneType type, Enum step, QuestTier quest) { super(name, baseDescription, icon); this.type = type; this.step = step; @@ -24,7 +24,7 @@ public MilestoneQuest(String name, List baseDescription, Material icon, )); } - public MilestoneQuest(String name, List baseDescription, ItemStack icon, MilestoneType type, Enum step, QuestTier quest) { + public MilestoneQuest(String name, List baseDescription, ItemStack icon, MilestoneType type, Enum step, QuestTier quest) { this(name, baseDescription, icon.getType(), type, step, quest); } } diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestoneStep.java b/src/main/java/fr/openmc/core/features/milestones/MilestoneStep.java new file mode 100644 index 000000000..1478ad3b9 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/milestones/MilestoneStep.java @@ -0,0 +1,6 @@ +package fr.openmc.core.features.milestones; + +public interface MilestoneStep { + MilestoneQuest getQuest(); + +} diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestoneType.java b/src/main/java/fr/openmc/core/features/milestones/MilestoneType.java index 6979f390f..eb837a6f9 100644 --- a/src/main/java/fr/openmc/core/features/milestones/MilestoneType.java +++ b/src/main/java/fr/openmc/core/features/milestones/MilestoneType.java @@ -6,15 +6,12 @@ @Getter public enum MilestoneType { TUTORIAL( - new TutorialMilestone(), - true + new TutorialMilestone() ); - private final Milestone milestone; - private final boolean boosBar; + private final Milestone milestone; - MilestoneType(Milestone milestone, boolean bossBar) { + MilestoneType(Milestone milestone) { this.milestone = milestone; - this.boosBar = bossBar; } } diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestoneUtils.java b/src/main/java/fr/openmc/core/features/milestones/MilestoneUtils.java index e1e185e18..1ddd72c5f 100644 --- a/src/main/java/fr/openmc/core/features/milestones/MilestoneUtils.java +++ b/src/main/java/fr/openmc/core/features/milestones/MilestoneUtils.java @@ -1,60 +1,18 @@ package fr.openmc.core.features.milestones; -import fr.openmc.core.features.displays.bossbar.BossbarManager; -import fr.openmc.core.features.displays.bossbar.BossbarsType; -import fr.openmc.core.features.milestones.tutorial.TutorialBossBar; -import fr.openmc.core.features.milestones.tutorial.TutorialMilestone; -import fr.openmc.core.features.milestones.tutorial.TutorialStep; -import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; public class MilestoneUtils { - public static void completeStep(MilestoneType type, Player player, Enum step) { + public static void completeStep(MilestoneType type, Player player, Enum step) { int stepInt = step.ordinal() + 1; if (MilestonesManager.getPlayerStep(type, player) >= stepInt) return; MilestonesManager.setPlayerStep(type, player, stepInt); - MilestonesManager.getMilestoneData(type).get(player.getUniqueId()).setProgress(0); - - if (type != MilestoneType.TUTORIAL) return; //TODO Refaire les bossbars - - int maxStep = TutorialStep.values().length; - - if (stepInt >= maxStep) { - TutorialBossBar.hide(player); - BossbarManager.removeBossBar(BossbarsType.TUTORIAL, player); - return; - } - - TutorialBossBar.update( - player, - Component.text(TutorialBossBar.PLACEHOLDER_TUTORIAL_BOSSBAR.formatted( - (stepInt + 1), - TutorialStep.values()[stepInt].getQuest().getName(player.getUniqueId()) - )), - (float) (stepInt + 1) / maxStep - ); } - public static void setBossBar(Player player) { - int maxStep = TutorialStep.values().length; - int step = MilestonesManager.getPlayerStep(MilestoneType.TUTORIAL, player); - - if (step >= maxStep) return; - String progressStr = ""; - if (step == 0) { - progressStr = " (" + TutorialMilestone.playerData.get(player.getUniqueId()).getProgress() + " / 30)"; - } - - TutorialBossBar.addTutorialBossBarForPlayer( - player, - Component.text(TutorialBossBar.PLACEHOLDER_TUTORIAL_BOSSBAR.formatted( - step + 1, - TutorialStep.values()[step].getQuest().getName(player.getUniqueId()) + progressStr - )), - step == 0 ? (float) TutorialStep.BREAK_AYWENITE.getQuest().getProgress(player.getUniqueId()) / 30 : (float) (step + 1) / maxStep - ); + public static boolean hasFinishedMilestone(MilestoneType type, Player player) { + return MilestonesManager.getPlayerStep(type, player) >= type.getMilestone().getSteps().size(); } } diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java b/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java index fe9bc5672..11fcdb547 100644 --- a/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java +++ b/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java @@ -6,8 +6,9 @@ import com.j256.ormlite.table.TableUtils; import fr.openmc.core.CommandsManager; import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.displays.bossbar.BossbarManager; +import fr.openmc.core.features.milestones.bossbar.MilestoneBossBar; import fr.openmc.core.features.milestones.listeners.PlayerJoin; -import fr.openmc.core.features.milestones.tutorial.listeners.TutorialBossBarEvent; import fr.openmc.core.features.quests.objects.Quest; import org.bukkit.entity.Player; import org.bukkit.event.Listener; @@ -16,7 +17,7 @@ import java.util.*; public class MilestonesManager { - private static final Set milestones = new HashSet<>(); + private static final Set> milestones = new HashSet<>(); private static Dao millestoneDao; @@ -29,8 +30,7 @@ public static void init() { registerMilestoneCommand(); OMCPlugin.registerEvents( - new PlayerJoin(), - new TutorialBossBarEvent() + new PlayerJoin() ); } @@ -54,7 +54,7 @@ public static void loadMilestonesData() { for (MilestoneModel data : milestoneData) { MilestoneType type = MilestoneType.valueOf(data.getType()); - Milestone milestone = type.getMilestone(); + Milestone milestone = type.getMilestone(); milestone.getPlayerData().put(data.getUUID(), data); } } catch (SQLException e) { @@ -68,7 +68,7 @@ public static void loadMilestonesData() { */ public static void saveMilestonesData() { try { - for (Milestone milestone : milestones) { + for (Milestone milestone : milestones) { for (Map.Entry entry : milestone.getPlayerData().entrySet()) { MilestoneModel model = entry.getValue(); millestoneDao.createOrUpdate(model); @@ -83,7 +83,7 @@ public static void saveMilestonesData() { * Load the quest progress for each player of each milestone */ public static void loadMilestonesProgress() { - for (Milestone milestone : milestones) { + for (Milestone milestone : milestones) { // Pour tous les joueurs du milestone, la progression est chargée à l'étape actuelle for (Map.Entry playerData : milestone.getPlayerData().entrySet()) { int step = playerData.getValue().getStep(); @@ -102,7 +102,7 @@ public static void loadMilestonesProgress() { * @param milestone the milestone to get data for * @return a map of player UUIDs to their MilestoneModel */ - public static Map getMilestoneData(Milestone milestone) { + public static Map getMilestoneData(Milestone milestone) { return milestone.getPlayerData(); } @@ -160,7 +160,7 @@ public static void setPlayerStep(MilestoneType type, Player player, int step) { * Get all registered milestones. * @return a set of all registered milestones */ - public static Set getRegisteredMilestones() { + public static Set> getRegisteredMilestones() { return milestones; } @@ -169,12 +169,12 @@ public static Set getRegisteredMilestones() { * This method adds the provided milestone to the internal set and registers it quests. * @param milestone the milestone to register */ - public static void registerMilestone(Milestone milestone) { + public static void registerMilestone(Milestone milestone) { if (milestone == null) return; milestones.add(milestone); registerQuestMilestone(milestone); - + registerMilestoneBossBar(milestone); } /** @@ -190,11 +190,19 @@ public static void registerMilestoneCommand() { * This method iterates through the steps of the milestone and registers any Listener instances. * @param milestone the milestone whose quests are to be registered */ - public static void registerQuestMilestone(Milestone milestone) { - for (Quest quest : milestone.getSteps()) { + public static void registerQuestMilestone(Milestone milestone) { + for (MilestoneQuest quest : milestone.getSteps()) { if (quest instanceof Listener listener) { OMCPlugin.registerEvents(listener); } } } + + public static void registerMilestoneBossBar(Milestone milestone) { + if (milestone.getBossBarOptions() == null) return; + + BossbarManager.registerBossbars( + new MilestoneBossBar(milestone) + ); + } } diff --git a/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBar.java b/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBar.java new file mode 100644 index 000000000..c0feddfb5 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBar.java @@ -0,0 +1,85 @@ +package fr.openmc.core.features.milestones.bossbar; + +import fr.openmc.core.features.displays.bossbar.BaseBossbar; +import fr.openmc.core.features.milestones.*; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; + +public class MilestoneBossBar extends BaseBossbar { + + private final Milestone milestone; + + public MilestoneBossBar(Milestone milestone) { + this.milestone = milestone; + } + public static final String PLACEHOLDER_MILESTONE_BOSSBAR = "§6Étape %s : %s"; + public static final String PLACEHOLDER_MILESTONE_BOSSBAR_PROGRESS = "§6Étape %s : %s (%s/%s)"; + + @Override + protected String id() { + return "omc:" + milestone.getType().toString() + "_milestone"; + } + + @Override + protected void update(Player player, BossBar bar) { + int currentStep = MilestonesManager.getPlayerStep(milestone.getType(), player); + + MilestoneStep[] steps = milestone.getStepEnum(); + + if (currentStep >= steps.length) return; // pas affiché par défaut (shouldDisplay()) + + int maxStep = steps.length; + MilestoneStep step = steps[currentStep]; + MilestoneQuest quest = step.getQuest(); + + int progress = quest.getProgress(player.getUniqueId()); + int goal = quest.getCurrentTarget(player.getUniqueId()); + + String questName = quest.getName(player.getUniqueId()); + + if (goal <= 1) { + bar.name(Component.text( + PLACEHOLDER_MILESTONE_BOSSBAR.formatted(currentStep + 1, questName) + )); + + bar.progress((float) currentStep / maxStep); + } else { + bar.name(Component.text( + PLACEHOLDER_MILESTONE_BOSSBAR_PROGRESS.formatted( + currentStep + 1, + quest.getName(player.getUniqueId()), + progress, + goal + ) + )); + + bar.progress((float) progress / goal); + } + } + + @Override + protected BossBar.Color color(Player player) { + return milestone.getBossBarOptions().color(); + } + + @Override + protected BossBar.Overlay style(Player player) { + return milestone.getBossBarOptions().style(); + } + + @Override + protected boolean shouldDisplay(Player player) { + return milestone.shouldDisplayBossBar(player); + } + + @Override + protected int weight() { + return 5; + } + + @Override + protected Integer updateInterval() { + return 2; + } +} diff --git a/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBarOptions.java b/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBarOptions.java new file mode 100644 index 000000000..23a3d240a --- /dev/null +++ b/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBarOptions.java @@ -0,0 +1,5 @@ +package fr.openmc.core.features.milestones.bossbar; + +import net.kyori.adventure.bossbar.BossBar; + +public record MilestoneBossBarOptions(BossBar.Color color, BossBar.Overlay style) { } diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialBossBar.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialBossBar.java deleted file mode 100644 index 5607cb084..000000000 --- a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialBossBar.java +++ /dev/null @@ -1,54 +0,0 @@ -package fr.openmc.core.features.milestones.tutorial; - -import fr.openmc.core.features.displays.bossbar.BossbarManager; -import fr.openmc.core.features.displays.bossbar.BossbarsType; -import net.kyori.adventure.bossbar.BossBar; -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; - -public class TutorialBossBar { - - public static final String PLACEHOLDER_TUTORIAL_BOSSBAR = "§6Étape %s : %s"; - - /** - * Adds a tutorial boss bar for the player with the given message and progress. - * - * @param player The player to add the boss bar for. - * @param message The message to display on the boss bar. - * @param progress The progress of the tutorial step (0.0 to 1.0). - */ - public static void addTutorialBossBarForPlayer(Player player, Component message, float progress) { - BossBar bar = BossBar.bossBar( - message, - progress, - BossBar.Color.YELLOW, - BossBar.Overlay.PROGRESS - ); - BossbarManager.addBossBar(BossbarsType.TUTORIAL, bar, player); - } - - /** - * Updates the tutorial boss bar for the player with the given message and progress. - * - * @param player The player to update the boss bar for. - * @param message The new message to display on the boss bar. - * @param progress The new progress of the tutorial step (0.0 to 1.0). - */ - public static void update(Player player, Component message, float progress) { - BossBar bar = BossbarManager.getBossBar(BossbarsType.TUTORIAL, player); - - if (bar != null) { - bar.name(message); - bar.progress(progress); - } - } - - /** - * Hides the tutorial boss bar for the player. - * - * @param player The player to hide the boss bar for. - */ - public static void hide(Player player) { - BossbarManager.removeBossBar(BossbarsType.TUTORIAL, player); - } -} diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialMilestone.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialMilestone.java index eb927ae9f..eb7156448 100644 --- a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialMilestone.java +++ b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialMilestone.java @@ -1,10 +1,11 @@ package fr.openmc.core.features.milestones.tutorial; import fr.openmc.api.menulib.Menu; -import fr.openmc.core.features.milestones.Milestone; -import fr.openmc.core.features.milestones.MilestoneQuest; -import fr.openmc.core.features.milestones.MilestoneType; +import fr.openmc.core.features.dream.DreamUtils; +import fr.openmc.core.features.milestones.*; +import fr.openmc.core.features.milestones.bossbar.MilestoneBossBarOptions; import fr.openmc.core.features.milestones.menus.MilestoneMenu; +import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -13,7 +14,7 @@ import java.util.Arrays; import java.util.List; -public class TutorialMilestone implements Milestone { +public class TutorialMilestone implements Milestone { @Override public String getName() { return "§7Tutoriel d'OpenMC"; @@ -35,8 +36,8 @@ public ItemStack getIcon() { } @Override - public List getSteps() { - return Arrays.stream(TutorialStep.values()).map(TutorialStep::getQuest).toList(); + public Class getStepClass() { + return TutorialStep.class; } @Override @@ -48,4 +49,17 @@ public MilestoneType getType() { public Menu getMenu(Player player) { return new MilestoneMenu(player, this); } + + @Override + public MilestoneBossBarOptions getBossBarOptions() { + return new MilestoneBossBarOptions( + BossBar.Color.YELLOW, + BossBar.Overlay.PROGRESS + ); + } + + @Override + public boolean shouldDisplayBossBar(Player player) { + return !DreamUtils.isInDreamWorld(player) && !MilestoneUtils.hasFinishedMilestone(this.getType(), player); + } } diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialStep.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialStep.java index ffb679a54..a6801e1ee 100644 --- a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialStep.java +++ b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialStep.java @@ -1,11 +1,12 @@ package fr.openmc.core.features.milestones.tutorial; import fr.openmc.core.features.milestones.MilestoneQuest; +import fr.openmc.core.features.milestones.MilestoneStep; import fr.openmc.core.features.milestones.tutorial.quests.*; import lombok.Getter; @Getter -public enum TutorialStep { +public enum TutorialStep implements MilestoneStep { BREAK_AYWENITE(null), CITY_CREATE(null), CITY_LEVEL_2(null), diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/listeners/TutorialBossBarEvent.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/listeners/TutorialBossBarEvent.java deleted file mode 100644 index 85db1ea27..000000000 --- a/src/main/java/fr/openmc/core/features/milestones/tutorial/listeners/TutorialBossBarEvent.java +++ /dev/null @@ -1,25 +0,0 @@ -package fr.openmc.core.features.milestones.tutorial.listeners; - -import fr.openmc.core.features.displays.bossbar.BossbarManager; -import fr.openmc.core.features.displays.bossbar.BossbarsType; -import fr.openmc.core.features.milestones.MilestoneUtils; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerQuitEvent; - -public class TutorialBossBarEvent implements Listener { - - @EventHandler - void onPlayerJoin(PlayerJoinEvent event) { - Player player = event.getPlayer(); - - MilestoneUtils.setBossBar(player); - } - - @EventHandler - public void onPlayerQuit(PlayerQuitEvent event) { - BossbarManager.removeBossBar(BossbarsType.TUTORIAL, event.getPlayer()); - } -} diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/BreakAyweniteQuest.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/BreakAyweniteQuest.java index db0e67e76..252f04189 100644 --- a/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/BreakAyweniteQuest.java +++ b/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/BreakAyweniteQuest.java @@ -3,10 +3,10 @@ import dev.lone.itemsadder.api.CustomBlock; import fr.openmc.api.hooks.ItemsAdderHook; import fr.openmc.core.features.city.CityManager; +import fr.openmc.core.features.displays.bossbar.BossbarManager; import fr.openmc.core.features.milestones.MilestoneQuest; import fr.openmc.core.features.milestones.MilestoneType; import fr.openmc.core.features.milestones.MilestonesManager; -import fr.openmc.core.features.milestones.tutorial.TutorialBossBar; import fr.openmc.core.features.milestones.tutorial.TutorialStep; import fr.openmc.core.features.quests.objects.QuestTier; import fr.openmc.core.features.quests.rewards.QuestMethodsReward; @@ -15,6 +15,7 @@ import fr.openmc.core.registry.items.CustomItemRegistry; import fr.openmc.core.utils.messages.MessageType; import fr.openmc.core.utils.messages.Prefix; +import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -64,19 +65,7 @@ public void onPlayerBreakBlock(BlockBreakEvent event) { ) { Player player = event.getPlayer(); this.incrementProgress(player.getUniqueId()); - getType().getMilestone().getPlayerData().get(player.getUniqueId()).incrementProgress(); - - int progress = this.getProgress(player.getUniqueId()); - - if (progress >= 30) return; - TutorialBossBar.update( - player, - Component.text(TutorialBossBar.PLACEHOLDER_TUTORIAL_BOSSBAR.formatted( - (step.ordinal() + 1), - TutorialStep.values()[step.ordinal()].getQuest().getName(player.getUniqueId()) + " (" + progress + " / 30)" - )), - (float) this.getProgress(player.getUniqueId()) / 30 - ); + this.getType().getMilestone().getPlayerData().get(player.getUniqueId()).incrementProgress(); } } } From ceffac3aefd7bc8f312d9aa38c3bd2be5d0ff43f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=C3=A9o=20B=2E?= Date: Wed, 18 Mar 2026 19:58:10 +0100 Subject: [PATCH 35/52] =?UTF-8?q?Revert=20"Rewrite=20de=20la=20base=20des?= =?UTF-8?q?=20boss=20bars=20+=20impl=C3=A9mentation=20boss=20bar=20dans=20?= =?UTF-8?q?miles=E2=80=A6"=20(#1208)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 09d4552e24219f1ed7736fe2c94487a2979e7e3d. --- .../java/fr/openmc/core/ListenersManager.java | 2 + src/main/java/fr/openmc/core/OMCPlugin.java | 2 - .../displays/bossbar/BaseBossbar.java | 57 --- .../displays/bossbar/BossbarManager.java | 344 +++++++++++------- .../bossbar/commands/BossBarCommand.java | 138 ++++++- .../bossbar/contents/HelpConfigManager.java | 67 ---- .../bossbar/contents/MainBossbar.java | 51 --- .../bossbar/listeners/BossbarListener.java | 23 ++ .../features/dream/displays/DreamBossBar.java | 76 ++-- .../dream/PlayerChangeWorldListener.java | 14 + .../listeners/dream/PlayerJoinListener.java | 8 + .../features/dream/models/db/DreamPlayer.java | 3 + .../core/features/milestones/Milestone.java | 46 +-- .../features/milestones/MilestoneQuest.java | 6 +- .../features/milestones/MilestoneStep.java | 6 - .../features/milestones/MilestoneType.java | 9 +- .../features/milestones/MilestoneUtils.java | 48 ++- .../milestones/MilestonesManager.java | 34 +- .../milestones/bossbar/MilestoneBossBar.java | 85 ----- .../bossbar/MilestoneBossBarOptions.java | 5 - .../milestones/tutorial/TutorialBossBar.java | 54 +++ .../tutorial/TutorialMilestone.java | 26 +- .../milestones/tutorial/TutorialStep.java | 3 +- .../listeners/TutorialBossBarEvent.java | 25 ++ .../tutorial/quests/BreakAyweniteQuest.java | 17 +- 25 files changed, 614 insertions(+), 535 deletions(-) delete mode 100644 src/main/java/fr/openmc/core/features/displays/bossbar/BaseBossbar.java delete mode 100644 src/main/java/fr/openmc/core/features/displays/bossbar/contents/HelpConfigManager.java delete mode 100644 src/main/java/fr/openmc/core/features/displays/bossbar/contents/MainBossbar.java create mode 100644 src/main/java/fr/openmc/core/features/displays/bossbar/listeners/BossbarListener.java delete mode 100644 src/main/java/fr/openmc/core/features/milestones/MilestoneStep.java delete mode 100644 src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBar.java delete mode 100644 src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBarOptions.java create mode 100644 src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialBossBar.java create mode 100644 src/main/java/fr/openmc/core/features/milestones/tutorial/listeners/TutorialBossBarEvent.java diff --git a/src/main/java/fr/openmc/core/ListenersManager.java b/src/main/java/fr/openmc/core/ListenersManager.java index 1ea12e498..c4a5a44d1 100644 --- a/src/main/java/fr/openmc/core/ListenersManager.java +++ b/src/main/java/fr/openmc/core/ListenersManager.java @@ -5,6 +5,7 @@ import fr.openmc.core.features.cube.listeners.CubeListener; import fr.openmc.core.features.cube.listeners.RepulseEffectListener; import fr.openmc.core.features.cube.multiblocks.MultiBlocksListeners; +import fr.openmc.core.features.displays.bossbar.listeners.BossbarListener; import fr.openmc.core.features.itemsadder.SpawnerExtractorListener; import fr.openmc.core.features.settings.PlayerSettingsManager; import fr.openmc.core.features.tickets.TicketListener; @@ -33,6 +34,7 @@ public static void init() { new SleepListener(), new PlayerDeathListener(), new AsyncChatListener(OMCPlugin.getInstance()), + new BossbarListener(), new PlayerSettingsManager(), new InteractListener(), new EquipableItemListener(), diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index ac1fbb50c..3518e9882 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -19,7 +19,6 @@ import fr.openmc.core.features.cube.multiblocks.MultiBlockManager; import fr.openmc.core.features.displays.TabList; import fr.openmc.core.features.displays.bossbar.BossbarManager; -import fr.openmc.core.features.displays.bossbar.contents.HelpConfigManager; import fr.openmc.core.features.displays.holograms.HologramLoader; import fr.openmc.core.features.displays.scoreboards.ScoreboardManager; import fr.openmc.core.features.dream.DreamManager; @@ -135,7 +134,6 @@ public void onEnable() { QuestProgressSaveManager.init(); TabList.init(); AdminShopManager.init(); - HelpConfigManager.init(); BossbarManager.init(); AnimationsManager.init(); HalloweenManager.init(); diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/BaseBossbar.java b/src/main/java/fr/openmc/core/features/displays/bossbar/BaseBossbar.java deleted file mode 100644 index 8f4ef79d3..000000000 --- a/src/main/java/fr/openmc/core/features/displays/bossbar/BaseBossbar.java +++ /dev/null @@ -1,57 +0,0 @@ -package fr.openmc.core.features.displays.bossbar; - -import net.kyori.adventure.bossbar.BossBar; -import org.bukkit.boss.BarColor; -import org.bukkit.entity.Player; - -public abstract class BaseBossbar { - /** - * Initialise la boss bar pour un joueur - * - * @param player Le joueur - */ - public void init(Player player, BossBar bar) { - update(player, bar); - } - - protected abstract String id(); - - /** - * Met à jour la boss bar - * - * @param player Le joueur - */ - protected abstract void update(Player player, BossBar bar); - - /** - * Détermine la couleur de la boss bar - * @param player Le joueur - * @return La couleur de la boss bar - */ - protected abstract BossBar.Color color(Player player); - - /** - * Détermine le style de la boss bar - * @param player Le joueur - * @return Le style de la boss bar - */ - protected abstract BossBar.Overlay style(Player player); - - /** - * Détermine si le boss bar doit être affiché pour un joueur - * - * @param player Le joueur à vérifier - * @return true si la boss bar doit être affiché, false sinon - */ - protected abstract boolean shouldDisplay(Player player); - - /** - * @return Le poids de la boss bar (plus la valeur est haute, plus la position de la boss bar sera haute). - */ - protected abstract int weight(); - - /** - * @return L'intervalle de mise à jour en secondes - */ - protected abstract Integer updateInterval(); -} diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/BossbarManager.java b/src/main/java/fr/openmc/core/features/displays/bossbar/BossbarManager.java index f6b30bc53..1c1b003fd 100644 --- a/src/main/java/fr/openmc/core/features/displays/bossbar/BossbarManager.java +++ b/src/main/java/fr/openmc/core/features/displays/bossbar/BossbarManager.java @@ -3,9 +3,10 @@ import fr.openmc.core.CommandsManager; import fr.openmc.core.OMCPlugin; import fr.openmc.core.features.displays.bossbar.commands.BossBarCommand; -import fr.openmc.core.features.displays.bossbar.contents.MainBossbar; -import fr.openmc.core.features.displays.scoreboards.BaseScoreboard; -import fr.openmc.core.features.dream.displays.DreamBossBar; +import fr.openmc.core.features.milestones.MilestoneUtils; +import fr.openmc.core.utils.messages.MessageType; +import fr.openmc.core.utils.messages.MessagesManager; +import fr.openmc.core.utils.messages.Prefix; import lombok.Getter; import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; @@ -19,174 +20,267 @@ import java.util.*; public class BossbarManager { - private static final List registeredBossbar = new ArrayList<>(); - - private static final Map> activeBossbars = new HashMap<>(); - private static final Map> lastUpdate = new HashMap<>(); - private static final Map> offBossbars = new HashMap<>(); - + @Getter + private static final List helpMessages = new ArrayList<>(); + private static final HashMap> activeBossBars = new HashMap<>(); + private static final Map playerPreferences = new HashMap<>(); + @Getter + private static boolean bossBarEnabled = true; + @Getter + private static File configFile; + private static int currentMessageIndex = 0; + + public static BossBar bossBarHelp; + + /** + * Initializes the BossbarManager + */ public static void init() { + configFile = new File(OMCPlugin.getInstance().getDataFolder() + "/data", "bossbars.yml"); + loadConfig(); + loadDefaultMessages(); + startRotationTask(); CommandsManager.getHandler().register(new BossBarCommand()); - registerBossbars( - new MainBossbar(), - new DreamBossBar() + bossBarHelp = BossBar.bossBar( + helpMessages.getFirst(), + 0f, + BossBar.Color.RED, + BossBar.Overlay.PROGRESS ); + } - start(); + /** + * Loads configuration from bossbars.yml file + * Creates the file if it doesn't exist + */ + private static void loadConfig() { + if (!configFile.exists()) { + configFile.getParentFile().mkdirs(); + OMCPlugin.getInstance().saveResource("data/bossbars.yml", false); + } + reloadMessages(); } - public static void registerBossbars(BaseBossbar... bossbar) { - registeredBossbar.addAll(Arrays.asList(bossbar)); - registeredBossbar.sort(Comparator.comparingInt(BaseBossbar::weight).reversed()); + /** + * Loads messages from the configuration file + */ + private static void loadDefaultMessages() { + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + helpMessages.clear(); + + for (String rawMessage : config.getStringList("messages")) { + helpMessages.add(MiniMessage.miniMessage().deserialize(rawMessage)); + } + + if (helpMessages.isEmpty()) { + OMCPlugin.getInstance().getSLF4JLogger().warn("No messages found in bossbars.yml."); + } } - private static void start() { + /** + * Starts the message rotation task for bossbars + * Messages change every 10 seconds (200 ticks) + */ + private static void startRotationTask() { new BukkitRunnable() { @Override public void run() { - for (Player player : Bukkit.getOnlinePlayers()) { - updatePlayer(player); - } - } - }.runTaskTimer(OMCPlugin.getInstance(), 0L, 20L); - } - + if (helpMessages.isEmpty()) return; - private static void updatePlayer(Player player) { + currentMessageIndex = (currentMessageIndex + 1) % helpMessages.size(); + Component message = helpMessages.get(currentMessageIndex); - UUID uuid = player.getUniqueId(); - - activeBossbars.putIfAbsent(uuid, new HashMap<>()); - offBossbars.putIfAbsent(uuid, new HashSet<>()); - lastUpdate.putIfAbsent(uuid, new HashMap<>()); - - Map playerBars = activeBossbars.get(uuid); - Set toggled = offBossbars.get(uuid); - Map playerLastUpdate = lastUpdate.get(uuid); + activeBossBars.forEach((type, bossBarData) -> { + if (!type.equals(BossbarsType.HELP)) return; - long now = System.currentTimeMillis(); - - for (BaseBossbar base : registeredBossbar) { - String id = base.id(); - - if (toggled.contains(id)) { - removeBossBar(player, id); - continue; + bossBarData.forEach((uuid, bossBar) -> { + if (bossBar != null) { + bossBar.name(message); + } + }); + }); } + }.runTaskTimer(OMCPlugin.getInstance(), 0, 200); + } - boolean shouldDisplay = base.shouldDisplay(player); - BossBar existing = playerBars.get(id); - - if (shouldDisplay) { + /** + * Adds a bossbar to the specified player + * @param type The type of bossbar to add + * @param bossbar The bossbar to add + * @param player The player to add the bossbar to + */ + public static void addBossBar(BossbarsType type, BossBar bossbar, Player player) { + if (!bossBarEnabled) return; + + Map bars = activeBossBars.get(type); + if (bars != null && bars.containsKey(player.getUniqueId())) return; + + Boolean preference = playerPreferences.get(player.getUniqueId()); + if (preference != null && !preference) { + return; + } + removeBossBar(type, player); - if (existing == null) { - existing = BossBar.bossBar( - Component.text(), - 1f, - base.color(player), - base.style(player) - ); + player.showBossBar(bossbar); + activeBossBars.computeIfAbsent(type, k -> new HashMap<>()).put(player.getUniqueId(), bossbar); + } - player.showBossBar(existing); - playerBars.put(id, existing); + /** + * Removes the bossbar from the specified player + * @param type The type of bossbar to remove + * @param player The player to remove the bossbar from + */ + public static void removeBossBar(BossbarsType type, Player player) { + Map map = activeBossBars.get(type); + if (map == null) return; + + BossBar bossBar = map.remove(player.getUniqueId()); + if (bossBar != null) { + player.hideBossBar(bossBar); + } + } - base.update(player, existing); - playerLastUpdate.put(id, now); - continue; - } + /** + * Gets the bossbar for a specific player + * + * @param type The type of bossbar to get + * @param player The player to get the bossbar for + * @return The bossbar for the specified player, or null if not found + */ + public static BossBar getBossBar(BossbarsType type, Player player) { + if (activeBossBars.get(type) == null) return null; - long last = playerLastUpdate.getOrDefault(id, 0L); - long intervalMillis = base.updateInterval() * 1000L; + return activeBossBars.get(type).get(player.getUniqueId()); - if (now - last >= intervalMillis) { - base.update(player, existing); - playerLastUpdate.put(id, now); - } + } + /** + * Toggles the bossbar for a specific player + * @param player The player to toggle the bossbar for + */ + public static void toggleBossBar(Player player) { + UUID uuid = player.getUniqueId(); + boolean enabled = false; + + for (Map.Entry> activeBossBar : activeBossBars.entrySet()) { + BossbarsType type = activeBossBar.getKey(); + Map bossBarData = activeBossBar.getValue(); + if (bossBarData.containsKey(uuid)) { + removeBossBar(type, player); + enabled = false; + playerPreferences.put(uuid, false); } else { - removeBossBar(player, id); - playerLastUpdate.remove(id); + switch (type) { + case HELP -> { + addBossBar(type, bossBarHelp, player); + enabled = true; + playerPreferences.put(uuid, true); + } + + case TUTORIAL -> { + MilestoneUtils.setBossBar(player); + enabled = true; + playerPreferences.put(uuid, true); + } + } } } - } - - public static void addBossBar(Player player, String id) { - BaseBossbar base = getRegistered(id); - if (base == null) return; - activeBossbars.putIfAbsent(player.getUniqueId(), new HashMap<>()); - - Map playerBars = activeBossbars.get(player.getUniqueId()); + if (enabled) { + MessagesManager.sendMessage(player, Component.text("Bossbar activée"), Prefix.OPENMC, MessageType.SUCCESS, true); + } else { + MessagesManager.sendMessage(player, Component.text("Bossbar désactivée"), Prefix.OPENMC, MessageType.WARNING, true); + } + } - if (playerBars.containsKey(id)) return; + /** + * Reloads messages from the configuration file + */ + public static void reloadMessages() { + helpMessages.clear(); + loadDefaultMessages(); + } - BossBar bar = BossBar.bossBar( - Component.text(), - 1L, - base.color(player), - base.style(player) - ); + /** + * Checks if bossbars are globally enabled + * @return true if bossbars are enabled, false otherwise + */ + public static boolean hasBossBar() { + return bossBarEnabled; + } - player.showBossBar(bar); - playerBars.put(id, bar); + /** + * Sets the list of messages to display in bossbars + * @param messages The list of new messages + */ + public static void setHelpMessages(List messages) { + helpMessages.clear(); + helpMessages.addAll(messages); + saveMessagesToConfig(); } - public static void removeBossBar(Player player, String id) { - Map bars = activeBossbars.get(player.getUniqueId()); - if (bars == null) return; + /** + * Saves messages to the configuration file + */ + private static void saveMessagesToConfig() { + try { + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + List serializedMessages = new ArrayList<>(); - BossBar bar = bars.remove(id); + for (Component message : helpMessages) { + serializedMessages.add(MiniMessage.miniMessage().serialize(message)); + } - if (bar != null) { - player.hideBossBar(bar); + config.set("messages", serializedMessages); + config.save(configFile); + } catch (Exception e) { + OMCPlugin.getInstance().getSLF4JLogger().warn("Failed to save bossbar messages to config: {}", e.getMessage(), e); } } - public static BossBar getBossBar(Player player, String id) { - Map bars = activeBossbars.get(player.getUniqueId()); - if (bars == null) return null; - return bars.get(id); + /** + * Adds a message to the message list + * @param message The message to add + */ + public static void addMessage(Component message) { + helpMessages.add(message); + saveMessagesToConfig(); } - public static void toggleBossBar(Player player, String id) { - offBossbars.putIfAbsent(player.getUniqueId(), new HashSet<>()); - - Set toggled = offBossbars.get(player.getUniqueId()); - - if (toggled.contains(id)) { - toggled.remove(id); - } else { - toggled.add(id); - removeBossBar(player, id); + /** + * Removes a message from the message list + * @param index The index of the message to remove + */ + public static void removeMessage(int index) { + if (index >= 0 && index < helpMessages.size()) { + helpMessages.remove(index); + saveMessagesToConfig(); } } - public static void toggleAllBossBar(Player player) { - for (BaseBossbar baseBossbar : registeredBossbar) { - toggleBossBar(player, baseBossbar.id()); + /** + * Updates an existing message + * @param index The index of the message to update + * @param newMessage The new message content + */ + public static void updateMessage(int index, Component newMessage) { + if (index >= 0 && index < helpMessages.size()) { + helpMessages.set(index, newMessage); + saveMessagesToConfig(); } } - public static boolean isToggled(Player player, String id) { - return offBossbars.getOrDefault(player.getUniqueId(), Set.of()).contains(id); - } + /** + * Toggles bossbars globally for all players + */ + public static void toggleGlobalBossBar() { + bossBarEnabled = !bossBarEnabled; - public static void removePlayer(Player player) { - Map bars = activeBossbars.remove(player.getUniqueId()); - if (bars != null) { - for (BossBar bar : bars.values()) { - player.hideBossBar(bar); - } + if (bossBarEnabled) { + Bukkit.getOnlinePlayers().forEach(player -> addBossBar(BossbarsType.HELP, bossBarHelp, player)); + } else { + Bukkit.getOnlinePlayers().forEach(player -> removeBossBar(BossbarsType.HELP, player)); } - - offBossbars.remove(player.getUniqueId()); - } - - private static BaseBossbar getRegistered(String id) { - return registeredBossbar.stream() - .filter(b -> b.id().equalsIgnoreCase(id)) - .findFirst() - .orElse(null); } } diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/commands/BossBarCommand.java b/src/main/java/fr/openmc/core/features/displays/bossbar/commands/BossBarCommand.java index efb045e33..7d81d9960 100644 --- a/src/main/java/fr/openmc/core/features/displays/bossbar/commands/BossBarCommand.java +++ b/src/main/java/fr/openmc/core/features/displays/bossbar/commands/BossBarCommand.java @@ -25,7 +25,141 @@ public class BossBarCommand { @CommandPlaceholder() - public void mainCommand(Player player) { - BossbarManager.toggleBossBar(player, "omc:help"); + public void mainCommand(CommandSender sender) { + if (!(sender instanceof Player player)) { + MessagesManager.sendMessage(sender, MessagesManager.Message.NO_PERMISSION.getMessage(), Prefix.OPENMC, MessageType.ERROR, true); + return; + } + + BossbarManager.toggleBossBar(player); + } + + @CommandPermission("omc.admin.commands.bossbar.reload") + @Subcommand("reload") + public void reloadCommand(CommandSender sender) { + BossbarManager.reloadMessages(); + MessagesManager.sendMessage(sender, Component.text("§aBossbar rechargée avec succès !"), Prefix.OPENMC, MessageType.SUCCESS, true); + } + + @CommandPermission("omc.admin.commands.bossbar.toggle") + @Subcommand("toggle") + public void toggleCommand(CommandSender sender) { + BossbarManager.toggleGlobalBossBar(); + if (sender instanceof Player player) { + MessagesManager.sendMessage(player, Component.text("§aBossbar " + (BossbarManager.hasBossBar() ? "activée" : "désactivée") + " pour vous."), Prefix.OPENMC, MessageType.SUCCESS, true); + } + } + + @CommandPermission("omc.admin.commands.bossbar.manage") + @Subcommand("manage") + public void manageCommand(BukkitCommandActor actor) { + if (!(actor.sender() instanceof Player player)) { + return; + } + + List messages = BossbarManager.getHelpMessages(); + + Component header = Component.text("\n§6§lGestion des messages de la bossbar\n") + .color(NamedTextColor.GOLD) + .decorate(TextDecoration.BOLD); + + MessagesManager.sendMessage(player, header, Prefix.OPENMC, MessageType.NONE, false); + + Component addButton = Component.text("[Ajouter un message]") + .color(NamedTextColor.GREEN) + .clickEvent(ClickEvent.suggestCommand("/omcbossbar add ")) + .hoverEvent(HoverEvent.showText(Component.text("Cliquez pour ajouter un message"))); + + MessagesManager.sendMessage(player, addButton, Prefix.OPENMC, MessageType.NONE, false); + + for (int i = 0; i < messages.size(); i++) { + Component messageLine = Component.text((i + 1) + ". ", NamedTextColor.GRAY) + .append(messages.get(i)) + .append(Component.space()) + .append(createActionButton("✎ Éditer", "/omcbossbar edit " + i + " " + messages.get(i), NamedTextColor.YELLOW)) + .append(Component.space()) + .append(createActionButton("✖ Supprimer", "/omcbossbar confirm " + i, NamedTextColor.RED)); + + MessagesManager.sendMessage(player, messageLine, Prefix.OPENMC, MessageType.NONE, false); + } + + Component refreshButton = Component.text("\n[Rafraîchir]") + .color(NamedTextColor.BLUE) + .clickEvent(ClickEvent.runCommand("/omcbossbar manage")) + .hoverEvent(HoverEvent.showText(Component.text("Actualiser la liste"))); + + MessagesManager.sendMessage(player, refreshButton, Prefix.OPENMC, MessageType.NONE, false); + } + + private Component createActionButton(String text, String command, NamedTextColor color) { + return Component.text(text) + .color(color) + .clickEvent(ClickEvent.suggestCommand(command)) + .hoverEvent(HoverEvent.showText(Component.text("Exécuter : " + command))); + } + + @CommandPermission("omc.admin.commands.bossbar.manage") + @Subcommand("add") + public void addMessage( + BukkitCommandActor actor, + @Named("message") String message + ) { + try { + Component component = MiniMessage.miniMessage().deserialize(message); + BossbarManager.addMessage(component); + BossbarManager.reloadMessages(); + + MessagesManager.sendMessage(actor.sender(), Component.text("§aMessage ajouté avec succès !"), Prefix.OPENMC, MessageType.SUCCESS, true); + manageCommand(actor); + } catch (Exception e) { + MessagesManager.sendMessage(actor.sender(), Component.text("§cErreur lors de l'ajout du message ! Assurez-vous que le format est correct."), Prefix.OPENMC, MessageType.ERROR, true); + } + } + + @CommandPermission("omc.admin.commands.bossbar.manage") + @Subcommand("edit") + public void editMessage( + BukkitCommandActor actor, + @Named("index") int index, + @Named("message edité") String newMessage + ) { + try { + Component component = MiniMessage.miniMessage().deserialize(newMessage); + BossbarManager.updateMessage(index, component); + BossbarManager.reloadMessages(); + MessagesManager.sendMessage(actor.sender(), Component.text("§aMessage mis à jour avec succès !"), Prefix.OPENMC, MessageType.SUCCESS, true); + manageCommand(actor); + } catch (Exception e) { + MessagesManager.sendMessage(actor.sender(), Component.text("§cFormat de message ou index invalide !"), Prefix.OPENMC, MessageType.ERROR, true); + } + } + + @CommandPermission("omc.admin.commands.bossbar.manage") + @Subcommand("confirm") + public void confirmDelete( + BukkitCommandActor actor, + @Named("index") int index + ) { + Component confirmation = Component.text() + .append(Component.text("§eÊtes-vous sûr de vouloir supprimer ce message ?")) + .append(Component.text("[OUI]") + .color(NamedTextColor.RED) + .clickEvent(ClickEvent.runCommand("/omcbossbar delete " + index)) + .hoverEvent(HoverEvent.showText(Component.text("Confirmer la suppression")))) + .build(); + + actor.reply(confirmation); + } + + @CommandPermission("omc.admin.commands.bossbar.manage") + @Subcommand("delete") + public void deleteMessage( + BukkitCommandActor actor, + @Named("index") int index + ) { + BossbarManager.removeMessage(index); + BossbarManager.reloadMessages(); + MessagesManager.sendMessage(actor.sender(), Component.text("Message supprimé avec succès."), Prefix.OPENMC, MessageType.SUCCESS, true); + manageCommand(actor); } } diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/contents/HelpConfigManager.java b/src/main/java/fr/openmc/core/features/displays/bossbar/contents/HelpConfigManager.java deleted file mode 100644 index b4ea4d6b0..000000000 --- a/src/main/java/fr/openmc/core/features/displays/bossbar/contents/HelpConfigManager.java +++ /dev/null @@ -1,67 +0,0 @@ -package fr.openmc.core.features.displays.bossbar.contents; - -import fr.openmc.core.CommandsManager; -import fr.openmc.core.OMCPlugin; -import fr.openmc.core.features.displays.bossbar.commands.BossBarCommand; -import lombok.Getter; -import net.kyori.adventure.bossbar.BossBar; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.configuration.file.YamlConfiguration; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -public class HelpConfigManager { - - @Getter - private static final List helpMessages = new ArrayList<>(); - @Getter - private static File configFile; - - /** - * Initializes the HelpConfigManager by loading the configuration and default messages - */ - public static void init() { - configFile = new File(OMCPlugin.getInstance().getDataFolder() + "/data", "bossbars.yml"); - loadConfig(); - loadDefaultMessages(); - } - - /** - * Loads configuration from bossbars.yml file - * Creates the file if it doesn't exist - */ - private static void loadConfig() { - if (!configFile.exists()) { - configFile.getParentFile().mkdirs(); - OMCPlugin.getInstance().saveResource("data/bossbars.yml", false); - } - reloadMessages(); - } - - /** - * Loads messages from the configuration file - */ - private static void loadDefaultMessages() { - YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); - helpMessages.clear(); - - for (String rawMessage : config.getStringList("messages")) { - helpMessages.add(MiniMessage.miniMessage().deserialize(rawMessage)); - } - - if (helpMessages.isEmpty()) { - OMCPlugin.getInstance().getSLF4JLogger().warn("No messages found in bossbars.yml."); - } - } - - /** - * Reloads messages from the configuration file - */ - public static void reloadMessages() { - helpMessages.clear(); - loadDefaultMessages(); - } -} diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/contents/MainBossbar.java b/src/main/java/fr/openmc/core/features/displays/bossbar/contents/MainBossbar.java deleted file mode 100644 index f146dd2d7..000000000 --- a/src/main/java/fr/openmc/core/features/displays/bossbar/contents/MainBossbar.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.openmc.core.features.displays.bossbar.contents; - -import fr.openmc.core.features.displays.bossbar.BaseBossbar; -import fr.openmc.core.features.dream.DreamUtils; -import net.kyori.adventure.bossbar.BossBar; -import net.kyori.adventure.text.minimessage.MiniMessage; -import org.bukkit.entity.Player; - -import java.util.List; - -public class MainBossbar extends BaseBossbar { - - private static int indexMessage = 0; - - @Override - protected String id() { - return "omc:help"; - } - - @Override - protected void update(Player player, BossBar bar) { - indexMessage = (indexMessage + 1) % HelpConfigManager.getHelpMessages().size(); - - bar.name(HelpConfigManager.getHelpMessages().get(indexMessage)); - } - - @Override - protected BossBar.Color color(Player player) { - return BossBar.Color.RED; - } - - @Override - protected BossBar.Overlay style(Player player) { - return BossBar.Overlay.PROGRESS; - } - - @Override - protected boolean shouldDisplay(Player player) { - return !DreamUtils.isInDreamWorld(player); - } - - @Override - protected int weight() { - return 10; - } - - @Override - protected Integer updateInterval() { - return 20; - } -} diff --git a/src/main/java/fr/openmc/core/features/displays/bossbar/listeners/BossbarListener.java b/src/main/java/fr/openmc/core/features/displays/bossbar/listeners/BossbarListener.java new file mode 100644 index 000000000..45379736d --- /dev/null +++ b/src/main/java/fr/openmc/core/features/displays/bossbar/listeners/BossbarListener.java @@ -0,0 +1,23 @@ +package fr.openmc.core.features.displays.bossbar.listeners; + +import fr.openmc.core.features.displays.bossbar.BossbarManager; +import fr.openmc.core.features.displays.bossbar.BossbarsType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +import static fr.openmc.core.features.displays.bossbar.BossbarManager.bossBarHelp; + +public class BossbarListener implements Listener { + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + BossbarManager.addBossBar(BossbarsType.HELP, bossBarHelp, event.getPlayer()); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + BossbarManager.removeBossBar(BossbarsType.HELP, event.getPlayer()); + } +} diff --git a/src/main/java/fr/openmc/core/features/dream/displays/DreamBossBar.java b/src/main/java/fr/openmc/core/features/dream/displays/DreamBossBar.java index 246591489..cf3efd507 100644 --- a/src/main/java/fr/openmc/core/features/dream/displays/DreamBossBar.java +++ b/src/main/java/fr/openmc/core/features/dream/displays/DreamBossBar.java @@ -1,11 +1,7 @@ package fr.openmc.core.features.dream.displays; -import fr.openmc.core.features.displays.bossbar.BaseBossbar; import fr.openmc.core.features.displays.bossbar.BossbarManager; import fr.openmc.core.features.displays.bossbar.BossbarsType; -import fr.openmc.core.features.dream.DreamManager; -import fr.openmc.core.features.dream.DreamUtils; -import fr.openmc.core.features.dream.models.db.DreamPlayer; import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; @@ -15,45 +11,45 @@ * *

Cette classe permet d'ajouter, mettre à jour et cacher la BossBar associée à un joueur.

*/ -public class DreamBossBar extends BaseBossbar { - @Override - protected String id() { - return "omc:dream"; +public class DreamBossBar { + + private static final Component TEXTURE_BOSSBAR = Component.text(""); + + /** + * Ajoute une BossBar pour le joueur spécifié dans la Dimension des Rêves. + * + * @param player le joueur auquel ajouter la BossBar + * @param progress la progression de la BossBar + */ + public static void addDreamBossBarForPlayer(Player player, float progress) { + BossBar bar = BossBar.bossBar( + TEXTURE_BOSSBAR, + progress, + BossBar.Color.BLUE, + BossBar.Overlay.PROGRESS + ); + BossbarManager.addBossBar(BossbarsType.DREAM, bar, player); } - @Override - protected void update(Player player, BossBar bar) { - DreamPlayer dreamPlayer = DreamManager.getDreamPlayer(player); - - if (dreamPlayer == null) return; - - float progress = Math.min(1, (float) dreamPlayer.getDreamTime() / dreamPlayer.getMaxDreamTime()); - - bar.progress(progress); - } - - @Override - protected BossBar.Color color(Player player) { - return BossBar.Color.BLUE; - } - - @Override - protected BossBar.Overlay style(Player player) { - return BossBar.Overlay.PROGRESS; - } - - @Override - protected boolean shouldDisplay(Player player) { - return DreamUtils.isInDreamWorld(player); - } - - @Override - protected int weight() { - return 10; + /** + * Met à jour la progression de la BossBar pour le joueur spécifié. + * + * @param player le joueur dont la BossBar doit être mise à jour + * @param progress la nouvelle progression de la BossBar + */ + public static void update(Player player, float progress) { + BossBar bar = BossbarManager.getBossBar(BossbarsType.DREAM, player); + if (bar != null) { + bar.progress(progress); + } } - @Override - protected Integer updateInterval() { - return 1; + /** + * Cache (supprime) la BossBar du joueur spécifié. + * + * @param player le joueur dont la BossBar doit être supprimée + */ + public static void hide(Player player) { + BossbarManager.removeBossBar(BossbarsType.DREAM, player); } } diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerChangeWorldListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerChangeWorldListener.java index dd7393748..84ba003f7 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerChangeWorldListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerChangeWorldListener.java @@ -24,6 +24,10 @@ public void onDreamEntrered(PlayerTeleportEvent event) { if (!DreamUtils.isDreamWorld(event.getTo())) return; if (DreamUtils.isDreamWorld(event.getFrom())) return; + for (BossbarsType type : BossbarsType.values()) { + BossbarManager.removeBossBar(type, player); + } + try { DreamManager.addDreamPlayer(player, event.getFrom()); } catch (IOException e) { @@ -33,6 +37,8 @@ public void onDreamEntrered(PlayerTeleportEvent event) { DreamPlayer dreamPlayer = DreamManager.getDreamPlayer(player); if (dreamPlayer == null) return; + DreamBossBar.addDreamBossBarForPlayer(player, Math.min(1, (float) dreamPlayer.getDreamTime() / dreamPlayer.getMaxDreamTime())); + player.setFoodLevel(20); player.setSaturation(10.0f); AttributeInstance inst = player.getAttribute(Attribute.MAX_HEALTH); @@ -47,6 +53,14 @@ public void onDreamLeave(PlayerTeleportEvent event) { if (!DreamUtils.isDreamWorld(event.getFrom())) return; if (DreamUtils.isDreamWorld(event.getTo())) return; + for (BossbarsType type : BossbarsType.values()) { + if (type.equals(BossbarsType.DREAM)) continue; + + BossbarManager.addBossBar(type, BossbarManager.bossBarHelp, player); + } + + BossbarManager.removeBossBar(BossbarsType.DREAM, player); + DreamManager.removeDreamPlayer(player, event.getFrom()); } } diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerJoinListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerJoinListener.java index 80ada5d61..f507cec39 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerJoinListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerJoinListener.java @@ -23,6 +23,14 @@ public void onPlayerJoinInDream(PlayerJoinEvent event) { if (!DreamUtils.isInDreamWorld(player)) return; + for (BossbarsType type : BossbarsType.values()) { + if (type.equals(BossbarsType.DREAM)) continue; + + BossbarManager.addBossBar(type, BossbarManager.bossBarHelp, player); + } + + BossbarManager.removeBossBar(BossbarsType.DREAM, player); + try { DreamManager.preloadSavePlayer(player, player.getLocation()); } catch (IOException e) { diff --git a/src/main/java/fr/openmc/core/features/dream/models/db/DreamPlayer.java b/src/main/java/fr/openmc/core/features/dream/models/db/DreamPlayer.java index 65fe90834..530c48d22 100644 --- a/src/main/java/fr/openmc/core/features/dream/models/db/DreamPlayer.java +++ b/src/main/java/fr/openmc/core/features/dream/models/db/DreamPlayer.java @@ -98,7 +98,10 @@ public void scheduleTimeTask() { Bukkit.getServer().getPluginManager().callEvent(new DreamEndEvent(this.player)) ); this.cancelTimeTask(); + return; } + + DreamBossBar.update(player, Math.min(1, (float) this.getDreamTime() / this.getMaxDreamTime())); }, 0L, 20L); } diff --git a/src/main/java/fr/openmc/core/features/milestones/Milestone.java b/src/main/java/fr/openmc/core/features/milestones/Milestone.java index 6052e510c..8358b023b 100644 --- a/src/main/java/fr/openmc/core/features/milestones/Milestone.java +++ b/src/main/java/fr/openmc/core/features/milestones/Milestone.java @@ -1,18 +1,15 @@ package fr.openmc.core.features.milestones; import fr.openmc.api.menulib.Menu; -import fr.openmc.core.features.milestones.bossbar.MilestoneBossBarOptions; -import fr.openmc.core.features.milestones.tutorial.TutorialStep; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.UUID; -public interface Milestone & MilestoneStep> { +public interface Milestone { HashMap playerData = new HashMap<>(); /** @@ -45,18 +42,13 @@ default HashMap getPlayerData() { * @return The icon of the milestone. */ ItemStack getIcon(); - - /** - * @return The class of the steps for the milestone. - */ - Class getStepClass(); - + /** - * @return The enum constants of the step class for the milestone. + * Returns the steps of the milestone. + * + * @return A step list of the milestone. */ - default T[] getStepEnum() { - return this.getStepClass().getEnumConstants(); - } + List getSteps(); /** * Returns the Type of the Milestone @@ -72,30 +64,4 @@ default T[] getStepEnum() { * @return The menu for the milestone. */ Menu getMenu(Player player); - - /** - * Returns the boss bar options for the milestone. - * If set to null, no boss bar will be displayed for the milestone. - * - * @return The boss bar options for the milestone. - */ - MilestoneBossBarOptions getBossBarOptions(); - - /** - * Determines whether the boss bar should be displayed for the given player. - * - * @param player The player for whom to check if the boss bar should be displayed. - * @return true if the boss bar should be displayed for the player, false otherwise. - */ - boolean shouldDisplayBossBar(Player player); - /** - * Returns the steps of the milestone. - * - * @return A step list of the milestone. - */ - default List getSteps() { - T[] enumStep = this.getStepEnum(); - return Arrays.stream(enumStep).map(MilestoneStep::getQuest).toList(); - } - } diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestoneQuest.java b/src/main/java/fr/openmc/core/features/milestones/MilestoneQuest.java index f72576d79..fed40f108 100644 --- a/src/main/java/fr/openmc/core/features/milestones/MilestoneQuest.java +++ b/src/main/java/fr/openmc/core/features/milestones/MilestoneQuest.java @@ -13,9 +13,9 @@ public class MilestoneQuest extends Quest { protected final MilestoneType type; - protected final Enum step; + protected final Enum step; - public MilestoneQuest(String name, List baseDescription, Material icon, MilestoneType type, Enum step, QuestTier quest) { + public MilestoneQuest(String name, List baseDescription, Material icon, MilestoneType type, Enum step, QuestTier quest) { super(name, baseDescription, icon); this.type = type; this.step = step; @@ -24,7 +24,7 @@ public MilestoneQuest(String name, List baseDescription, Material icon, )); } - public MilestoneQuest(String name, List baseDescription, ItemStack icon, MilestoneType type, Enum step, QuestTier quest) { + public MilestoneQuest(String name, List baseDescription, ItemStack icon, MilestoneType type, Enum step, QuestTier quest) { this(name, baseDescription, icon.getType(), type, step, quest); } } diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestoneStep.java b/src/main/java/fr/openmc/core/features/milestones/MilestoneStep.java deleted file mode 100644 index 1478ad3b9..000000000 --- a/src/main/java/fr/openmc/core/features/milestones/MilestoneStep.java +++ /dev/null @@ -1,6 +0,0 @@ -package fr.openmc.core.features.milestones; - -public interface MilestoneStep { - MilestoneQuest getQuest(); - -} diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestoneType.java b/src/main/java/fr/openmc/core/features/milestones/MilestoneType.java index eb837a6f9..6979f390f 100644 --- a/src/main/java/fr/openmc/core/features/milestones/MilestoneType.java +++ b/src/main/java/fr/openmc/core/features/milestones/MilestoneType.java @@ -6,12 +6,15 @@ @Getter public enum MilestoneType { TUTORIAL( - new TutorialMilestone() + new TutorialMilestone(), + true ); - private final Milestone milestone; + private final Milestone milestone; + private final boolean boosBar; - MilestoneType(Milestone milestone) { + MilestoneType(Milestone milestone, boolean bossBar) { this.milestone = milestone; + this.boosBar = bossBar; } } diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestoneUtils.java b/src/main/java/fr/openmc/core/features/milestones/MilestoneUtils.java index 1ddd72c5f..e1e185e18 100644 --- a/src/main/java/fr/openmc/core/features/milestones/MilestoneUtils.java +++ b/src/main/java/fr/openmc/core/features/milestones/MilestoneUtils.java @@ -1,18 +1,60 @@ package fr.openmc.core.features.milestones; +import fr.openmc.core.features.displays.bossbar.BossbarManager; +import fr.openmc.core.features.displays.bossbar.BossbarsType; +import fr.openmc.core.features.milestones.tutorial.TutorialBossBar; +import fr.openmc.core.features.milestones.tutorial.TutorialMilestone; +import fr.openmc.core.features.milestones.tutorial.TutorialStep; +import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; public class MilestoneUtils { - public static void completeStep(MilestoneType type, Player player, Enum step) { + public static void completeStep(MilestoneType type, Player player, Enum step) { int stepInt = step.ordinal() + 1; if (MilestonesManager.getPlayerStep(type, player) >= stepInt) return; MilestonesManager.setPlayerStep(type, player, stepInt); + MilestonesManager.getMilestoneData(type).get(player.getUniqueId()).setProgress(0); + + if (type != MilestoneType.TUTORIAL) return; //TODO Refaire les bossbars + + int maxStep = TutorialStep.values().length; + + if (stepInt >= maxStep) { + TutorialBossBar.hide(player); + BossbarManager.removeBossBar(BossbarsType.TUTORIAL, player); + return; + } + + TutorialBossBar.update( + player, + Component.text(TutorialBossBar.PLACEHOLDER_TUTORIAL_BOSSBAR.formatted( + (stepInt + 1), + TutorialStep.values()[stepInt].getQuest().getName(player.getUniqueId()) + )), + (float) (stepInt + 1) / maxStep + ); } - public static boolean hasFinishedMilestone(MilestoneType type, Player player) { - return MilestonesManager.getPlayerStep(type, player) >= type.getMilestone().getSteps().size(); + public static void setBossBar(Player player) { + int maxStep = TutorialStep.values().length; + int step = MilestonesManager.getPlayerStep(MilestoneType.TUTORIAL, player); + + if (step >= maxStep) return; + String progressStr = ""; + if (step == 0) { + progressStr = " (" + TutorialMilestone.playerData.get(player.getUniqueId()).getProgress() + " / 30)"; + } + + TutorialBossBar.addTutorialBossBarForPlayer( + player, + Component.text(TutorialBossBar.PLACEHOLDER_TUTORIAL_BOSSBAR.formatted( + step + 1, + TutorialStep.values()[step].getQuest().getName(player.getUniqueId()) + progressStr + )), + step == 0 ? (float) TutorialStep.BREAK_AYWENITE.getQuest().getProgress(player.getUniqueId()) / 30 : (float) (step + 1) / maxStep + ); } } diff --git a/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java b/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java index 11fcdb547..fe9bc5672 100644 --- a/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java +++ b/src/main/java/fr/openmc/core/features/milestones/MilestonesManager.java @@ -6,9 +6,8 @@ import com.j256.ormlite.table.TableUtils; import fr.openmc.core.CommandsManager; import fr.openmc.core.OMCPlugin; -import fr.openmc.core.features.displays.bossbar.BossbarManager; -import fr.openmc.core.features.milestones.bossbar.MilestoneBossBar; import fr.openmc.core.features.milestones.listeners.PlayerJoin; +import fr.openmc.core.features.milestones.tutorial.listeners.TutorialBossBarEvent; import fr.openmc.core.features.quests.objects.Quest; import org.bukkit.entity.Player; import org.bukkit.event.Listener; @@ -17,7 +16,7 @@ import java.util.*; public class MilestonesManager { - private static final Set> milestones = new HashSet<>(); + private static final Set milestones = new HashSet<>(); private static Dao millestoneDao; @@ -30,7 +29,8 @@ public static void init() { registerMilestoneCommand(); OMCPlugin.registerEvents( - new PlayerJoin() + new PlayerJoin(), + new TutorialBossBarEvent() ); } @@ -54,7 +54,7 @@ public static void loadMilestonesData() { for (MilestoneModel data : milestoneData) { MilestoneType type = MilestoneType.valueOf(data.getType()); - Milestone milestone = type.getMilestone(); + Milestone milestone = type.getMilestone(); milestone.getPlayerData().put(data.getUUID(), data); } } catch (SQLException e) { @@ -68,7 +68,7 @@ public static void loadMilestonesData() { */ public static void saveMilestonesData() { try { - for (Milestone milestone : milestones) { + for (Milestone milestone : milestones) { for (Map.Entry entry : milestone.getPlayerData().entrySet()) { MilestoneModel model = entry.getValue(); millestoneDao.createOrUpdate(model); @@ -83,7 +83,7 @@ public static void saveMilestonesData() { * Load the quest progress for each player of each milestone */ public static void loadMilestonesProgress() { - for (Milestone milestone : milestones) { + for (Milestone milestone : milestones) { // Pour tous les joueurs du milestone, la progression est chargée à l'étape actuelle for (Map.Entry playerData : milestone.getPlayerData().entrySet()) { int step = playerData.getValue().getStep(); @@ -102,7 +102,7 @@ public static void loadMilestonesProgress() { * @param milestone the milestone to get data for * @return a map of player UUIDs to their MilestoneModel */ - public static Map getMilestoneData(Milestone milestone) { + public static Map getMilestoneData(Milestone milestone) { return milestone.getPlayerData(); } @@ -160,7 +160,7 @@ public static void setPlayerStep(MilestoneType type, Player player, int step) { * Get all registered milestones. * @return a set of all registered milestones */ - public static Set> getRegisteredMilestones() { + public static Set getRegisteredMilestones() { return milestones; } @@ -169,12 +169,12 @@ public static Set> getRegisteredMilestones() { * This method adds the provided milestone to the internal set and registers it quests. * @param milestone the milestone to register */ - public static void registerMilestone(Milestone milestone) { + public static void registerMilestone(Milestone milestone) { if (milestone == null) return; milestones.add(milestone); registerQuestMilestone(milestone); - registerMilestoneBossBar(milestone); + } /** @@ -190,19 +190,11 @@ public static void registerMilestoneCommand() { * This method iterates through the steps of the milestone and registers any Listener instances. * @param milestone the milestone whose quests are to be registered */ - public static void registerQuestMilestone(Milestone milestone) { - for (MilestoneQuest quest : milestone.getSteps()) { + public static void registerQuestMilestone(Milestone milestone) { + for (Quest quest : milestone.getSteps()) { if (quest instanceof Listener listener) { OMCPlugin.registerEvents(listener); } } } - - public static void registerMilestoneBossBar(Milestone milestone) { - if (milestone.getBossBarOptions() == null) return; - - BossbarManager.registerBossbars( - new MilestoneBossBar(milestone) - ); - } } diff --git a/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBar.java b/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBar.java deleted file mode 100644 index c0feddfb5..000000000 --- a/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBar.java +++ /dev/null @@ -1,85 +0,0 @@ -package fr.openmc.core.features.milestones.bossbar; - -import fr.openmc.core.features.displays.bossbar.BaseBossbar; -import fr.openmc.core.features.milestones.*; -import net.kyori.adventure.bossbar.BossBar; -import net.kyori.adventure.text.Component; -import org.bukkit.entity.Player; - -public class MilestoneBossBar extends BaseBossbar { - - private final Milestone milestone; - - public MilestoneBossBar(Milestone milestone) { - this.milestone = milestone; - } - public static final String PLACEHOLDER_MILESTONE_BOSSBAR = "§6Étape %s : %s"; - public static final String PLACEHOLDER_MILESTONE_BOSSBAR_PROGRESS = "§6Étape %s : %s (%s/%s)"; - - @Override - protected String id() { - return "omc:" + milestone.getType().toString() + "_milestone"; - } - - @Override - protected void update(Player player, BossBar bar) { - int currentStep = MilestonesManager.getPlayerStep(milestone.getType(), player); - - MilestoneStep[] steps = milestone.getStepEnum(); - - if (currentStep >= steps.length) return; // pas affiché par défaut (shouldDisplay()) - - int maxStep = steps.length; - MilestoneStep step = steps[currentStep]; - MilestoneQuest quest = step.getQuest(); - - int progress = quest.getProgress(player.getUniqueId()); - int goal = quest.getCurrentTarget(player.getUniqueId()); - - String questName = quest.getName(player.getUniqueId()); - - if (goal <= 1) { - bar.name(Component.text( - PLACEHOLDER_MILESTONE_BOSSBAR.formatted(currentStep + 1, questName) - )); - - bar.progress((float) currentStep / maxStep); - } else { - bar.name(Component.text( - PLACEHOLDER_MILESTONE_BOSSBAR_PROGRESS.formatted( - currentStep + 1, - quest.getName(player.getUniqueId()), - progress, - goal - ) - )); - - bar.progress((float) progress / goal); - } - } - - @Override - protected BossBar.Color color(Player player) { - return milestone.getBossBarOptions().color(); - } - - @Override - protected BossBar.Overlay style(Player player) { - return milestone.getBossBarOptions().style(); - } - - @Override - protected boolean shouldDisplay(Player player) { - return milestone.shouldDisplayBossBar(player); - } - - @Override - protected int weight() { - return 5; - } - - @Override - protected Integer updateInterval() { - return 2; - } -} diff --git a/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBarOptions.java b/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBarOptions.java deleted file mode 100644 index 23a3d240a..000000000 --- a/src/main/java/fr/openmc/core/features/milestones/bossbar/MilestoneBossBarOptions.java +++ /dev/null @@ -1,5 +0,0 @@ -package fr.openmc.core.features.milestones.bossbar; - -import net.kyori.adventure.bossbar.BossBar; - -public record MilestoneBossBarOptions(BossBar.Color color, BossBar.Overlay style) { } diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialBossBar.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialBossBar.java new file mode 100644 index 000000000..5607cb084 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialBossBar.java @@ -0,0 +1,54 @@ +package fr.openmc.core.features.milestones.tutorial; + +import fr.openmc.core.features.displays.bossbar.BossbarManager; +import fr.openmc.core.features.displays.bossbar.BossbarsType; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import org.bukkit.entity.Player; + +public class TutorialBossBar { + + public static final String PLACEHOLDER_TUTORIAL_BOSSBAR = "§6Étape %s : %s"; + + /** + * Adds a tutorial boss bar for the player with the given message and progress. + * + * @param player The player to add the boss bar for. + * @param message The message to display on the boss bar. + * @param progress The progress of the tutorial step (0.0 to 1.0). + */ + public static void addTutorialBossBarForPlayer(Player player, Component message, float progress) { + BossBar bar = BossBar.bossBar( + message, + progress, + BossBar.Color.YELLOW, + BossBar.Overlay.PROGRESS + ); + BossbarManager.addBossBar(BossbarsType.TUTORIAL, bar, player); + } + + /** + * Updates the tutorial boss bar for the player with the given message and progress. + * + * @param player The player to update the boss bar for. + * @param message The new message to display on the boss bar. + * @param progress The new progress of the tutorial step (0.0 to 1.0). + */ + public static void update(Player player, Component message, float progress) { + BossBar bar = BossbarManager.getBossBar(BossbarsType.TUTORIAL, player); + + if (bar != null) { + bar.name(message); + bar.progress(progress); + } + } + + /** + * Hides the tutorial boss bar for the player. + * + * @param player The player to hide the boss bar for. + */ + public static void hide(Player player) { + BossbarManager.removeBossBar(BossbarsType.TUTORIAL, player); + } +} diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialMilestone.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialMilestone.java index eb7156448..eb927ae9f 100644 --- a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialMilestone.java +++ b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialMilestone.java @@ -1,11 +1,10 @@ package fr.openmc.core.features.milestones.tutorial; import fr.openmc.api.menulib.Menu; -import fr.openmc.core.features.dream.DreamUtils; -import fr.openmc.core.features.milestones.*; -import fr.openmc.core.features.milestones.bossbar.MilestoneBossBarOptions; +import fr.openmc.core.features.milestones.Milestone; +import fr.openmc.core.features.milestones.MilestoneQuest; +import fr.openmc.core.features.milestones.MilestoneType; import fr.openmc.core.features.milestones.menus.MilestoneMenu; -import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -14,7 +13,7 @@ import java.util.Arrays; import java.util.List; -public class TutorialMilestone implements Milestone { +public class TutorialMilestone implements Milestone { @Override public String getName() { return "§7Tutoriel d'OpenMC"; @@ -36,8 +35,8 @@ public ItemStack getIcon() { } @Override - public Class getStepClass() { - return TutorialStep.class; + public List getSteps() { + return Arrays.stream(TutorialStep.values()).map(TutorialStep::getQuest).toList(); } @Override @@ -49,17 +48,4 @@ public MilestoneType getType() { public Menu getMenu(Player player) { return new MilestoneMenu(player, this); } - - @Override - public MilestoneBossBarOptions getBossBarOptions() { - return new MilestoneBossBarOptions( - BossBar.Color.YELLOW, - BossBar.Overlay.PROGRESS - ); - } - - @Override - public boolean shouldDisplayBossBar(Player player) { - return !DreamUtils.isInDreamWorld(player) && !MilestoneUtils.hasFinishedMilestone(this.getType(), player); - } } diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialStep.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialStep.java index a6801e1ee..ffb679a54 100644 --- a/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialStep.java +++ b/src/main/java/fr/openmc/core/features/milestones/tutorial/TutorialStep.java @@ -1,12 +1,11 @@ package fr.openmc.core.features.milestones.tutorial; import fr.openmc.core.features.milestones.MilestoneQuest; -import fr.openmc.core.features.milestones.MilestoneStep; import fr.openmc.core.features.milestones.tutorial.quests.*; import lombok.Getter; @Getter -public enum TutorialStep implements MilestoneStep { +public enum TutorialStep { BREAK_AYWENITE(null), CITY_CREATE(null), CITY_LEVEL_2(null), diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/listeners/TutorialBossBarEvent.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/listeners/TutorialBossBarEvent.java new file mode 100644 index 000000000..85db1ea27 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/milestones/tutorial/listeners/TutorialBossBarEvent.java @@ -0,0 +1,25 @@ +package fr.openmc.core.features.milestones.tutorial.listeners; + +import fr.openmc.core.features.displays.bossbar.BossbarManager; +import fr.openmc.core.features.displays.bossbar.BossbarsType; +import fr.openmc.core.features.milestones.MilestoneUtils; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class TutorialBossBarEvent implements Listener { + + @EventHandler + void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + + MilestoneUtils.setBossBar(player); + } + + @EventHandler + public void onPlayerQuit(PlayerQuitEvent event) { + BossbarManager.removeBossBar(BossbarsType.TUTORIAL, event.getPlayer()); + } +} diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/BreakAyweniteQuest.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/BreakAyweniteQuest.java index 252f04189..db0e67e76 100644 --- a/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/BreakAyweniteQuest.java +++ b/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/BreakAyweniteQuest.java @@ -3,10 +3,10 @@ import dev.lone.itemsadder.api.CustomBlock; import fr.openmc.api.hooks.ItemsAdderHook; import fr.openmc.core.features.city.CityManager; -import fr.openmc.core.features.displays.bossbar.BossbarManager; import fr.openmc.core.features.milestones.MilestoneQuest; import fr.openmc.core.features.milestones.MilestoneType; import fr.openmc.core.features.milestones.MilestonesManager; +import fr.openmc.core.features.milestones.tutorial.TutorialBossBar; import fr.openmc.core.features.milestones.tutorial.TutorialStep; import fr.openmc.core.features.quests.objects.QuestTier; import fr.openmc.core.features.quests.rewards.QuestMethodsReward; @@ -15,7 +15,6 @@ import fr.openmc.core.registry.items.CustomItemRegistry; import fr.openmc.core.utils.messages.MessageType; import fr.openmc.core.utils.messages.Prefix; -import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.text.Component; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -65,7 +64,19 @@ public void onPlayerBreakBlock(BlockBreakEvent event) { ) { Player player = event.getPlayer(); this.incrementProgress(player.getUniqueId()); - this.getType().getMilestone().getPlayerData().get(player.getUniqueId()).incrementProgress(); + getType().getMilestone().getPlayerData().get(player.getUniqueId()).incrementProgress(); + + int progress = this.getProgress(player.getUniqueId()); + + if (progress >= 30) return; + TutorialBossBar.update( + player, + Component.text(TutorialBossBar.PLACEHOLDER_TUTORIAL_BOSSBAR.formatted( + (step.ordinal() + 1), + TutorialStep.values()[step.ordinal()].getQuest().getName(player.getUniqueId()) + " (" + progress + " / 30)" + )), + (float) this.getProgress(player.getUniqueId()) / 30 + ); } } } From 8f883c43e6515e37746c80af66f3dc5ef95e209f Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 20:21:07 +0100 Subject: [PATCH 36/52] final fix? --- .github/workflows/milestone-close.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index a153a66bc..3f3519128 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -57,10 +57,10 @@ jobs: files: builds/** - name: Deploy to server - uses: rexlmanu/pterodactyl-upload-action@v2.5 + uses: blobles-dev/pterodactyl-upload-action@pterodactyl-file-upload-modification-allow-http-200-fileupload with: panel-host: ${{ secrets.PANEL_HOST }} api-key: ${{ secrets.API_KEY }} server-id: ${{ secrets.SERVER_ID }} - source: OpenMC.jar - target: "./plugins/update/OpenMC.jar" + source: builds/OpenMC.jar + target: "./plugins/update/" From b9d946e7aa52bdb1e16685ea7aaef4e7d3f821c9 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 18 Mar 2026 20:25:23 +0100 Subject: [PATCH 37/52] try to readd command on release? --- .github/workflows/milestone-close.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 3f3519128..8be8f3cc3 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -64,3 +64,4 @@ jobs: server-id: ${{ secrets.SERVER_ID }} source: builds/OpenMC.jar target: "./plugins/update/" + command: omcrestart From 8aa0787dc0540aeab95839d57bd8b0e87ddd00de Mon Sep 17 00:00:00 2001 From: Gtol <162237671+gtolontop@users.noreply.github.com> Date: Fri, 20 Mar 2026 17:30:16 +0100 Subject: [PATCH 38/52] fix: correction des tests unitaires et ajout de nouveau test (#1170) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: déplacement du SpawnerExtractorListener dans le guard isUnitTestVersion * chore: logs verbeux pour diagnostiquer les tests unitaires * fix: ignorer TabList dans les tests unitaires TabList utilise PacketAdapter de ProtocolLib (dépendance compileOnly), ce qui cause un ClassNotFoundException au lancement des tests MockBukkit. * fix: null check dans MultiBlockManager.save() MultiBlockManager.init() est appelé via loadWithItemsAdder() qui ne s'exécute pas en environnement de test. config reste null et provoque un NPE lors du onDisable. * fix: test MotdUtils flaky avec seulement 2 entrées MOTD Le BukkitRunnable (delay 0) s'exécute pendant le load du plugin, donc le MOTD capturé est déjà le custom. Avec 2 entrées dans motd.yml, Random peut piocher la même → assertNotEquals échoue 50% du temps. Fix: forcer un MOTD connu avant de tick. * fix: attendre les tâches async dans le test transferBalance Le test testTransferBalanceWithReasonRegistersTransaction échoue car la transaction est enregistrée via runTaskAsynchronously et performTicks ne garantit pas la fin des tâches async. Ajout de waitAsyncTasksFinished() pour attendre la complétion avant de vérifier. * test: ajout de tests unitaires pour les utilitaires et l'économie Nouveaux tests: - DateUtils: conversion secondes/millis/ticks, isBefore - InputUtils: pluralize, edge cases null/empty/décimaux - PaddingUtils: centrage, débordement, padding impair - EnumUtils: match valide/invalide/null, valeur par défaut - MathUtils: interpolation de couleurs (lerpColor) - YmlUtils: deep copy de maps/listes imbriquées - Queue: ajout, suppression, éviction LRU, taille max - ColorUtils: conversions couleur/code/nom/matériau/RGB - RandomUtils: bornes int/double/float, cas limites - EconomyManager: formatage simplifié (k/M/B suffixes) * fix: waitAsyncTasksFinished sur tous les tests de transactions Ajout de waitAsyncTasksFinished() après performTicks() dans tous les tests Economy qui vérifient des transactions enregistrées en async. * fix: déplacer le null check au début de MultiBlockManager.save() Évite d'itérer inutilement sur les multiblocks si config n'a pas été initialisé (init() appelé uniquement via loadWithItemsAdder). * fix: appliquer les retours de review PR #1170 - Suppression des performTicks redondants avant waitAsyncTasksFinished - Ajout de tests NaN, Infinity, -Infinity dans InputUtilsTest - Suppression du bloc testLogging de debug dans build.gradle - Fix locale EconomyFormattingTest pour éviter les échecs liés au séparateur décimal --- .../java/fr/openmc/core/ListenersManager.java | 2 +- src/main/java/fr/openmc/core/OMCPlugin.java | 3 +- .../cube/multiblocks/MultiBlockManager.java | 2 + .../economy/EconomyFormattingTest.java | 66 ++++++++++++++ .../features/economy/EconomyManagerTest.java | 12 +-- .../fr/openmc/core/utils/ColorUtilsTest.java | 78 ++++++++++++++++ .../fr/openmc/core/utils/DateUtilsTest.java | 84 +++++++++++++++-- .../fr/openmc/core/utils/EnumUtilsTest.java | 47 ++++++++++ .../fr/openmc/core/utils/InputUtilsTest.java | 82 +++++++++++------ .../fr/openmc/core/utils/MathUtilsTest.java | 52 +++++++++++ .../fr/openmc/core/utils/MotdUtilsTest.java | 2 +- .../openmc/core/utils/PaddingUtilsTest.java | 46 ++++++++++ .../java/fr/openmc/core/utils/QueueTest.java | 78 ++++++++++++++++ .../fr/openmc/core/utils/RandomUtilsTest.java | 47 ++++++++++ .../fr/openmc/core/utils/YmlUtilsTest.java | 89 +++++++++++++++++++ 15 files changed, 649 insertions(+), 41 deletions(-) create mode 100644 src/test/java/fr/openmc/core/features/economy/EconomyFormattingTest.java create mode 100644 src/test/java/fr/openmc/core/utils/ColorUtilsTest.java create mode 100644 src/test/java/fr/openmc/core/utils/EnumUtilsTest.java create mode 100644 src/test/java/fr/openmc/core/utils/MathUtilsTest.java create mode 100644 src/test/java/fr/openmc/core/utils/PaddingUtilsTest.java create mode 100644 src/test/java/fr/openmc/core/utils/QueueTest.java create mode 100644 src/test/java/fr/openmc/core/utils/RandomUtilsTest.java create mode 100644 src/test/java/fr/openmc/core/utils/YmlUtilsTest.java diff --git a/src/main/java/fr/openmc/core/ListenersManager.java b/src/main/java/fr/openmc/core/ListenersManager.java index c4a5a44d1..511e0a076 100644 --- a/src/main/java/fr/openmc/core/ListenersManager.java +++ b/src/main/java/fr/openmc/core/ListenersManager.java @@ -40,12 +40,12 @@ public static void init() { new EquipableItemListener(), new NoMoreRabbit(), new ArmorListener(), - new SpawnerExtractorListener(), new BlockBreakListener() ); if (!OMCPlugin.isUnitTestVersion()) { registerEvents( + new SpawnerExtractorListener(), new ItemsAddersListener(), new TicketListener() ); diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index 3518e9882..30d956fca 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -132,7 +132,8 @@ public void onEnable() { TPAQueue.initCommand(); FreezeManager.init(); QuestProgressSaveManager.init(); - TabList.init(); + if (!isUnitTestVersion()) + TabList.init(); AdminShopManager.init(); BossbarManager.init(); AnimationsManager.init(); diff --git a/src/main/java/fr/openmc/core/features/cube/multiblocks/MultiBlockManager.java b/src/main/java/fr/openmc/core/features/cube/multiblocks/MultiBlockManager.java index b1adcf75c..ca264d4e1 100644 --- a/src/main/java/fr/openmc/core/features/cube/multiblocks/MultiBlockManager.java +++ b/src/main/java/fr/openmc/core/features/cube/multiblocks/MultiBlockManager.java @@ -81,6 +81,8 @@ public static void load() { } public static void save() { + if (config == null) return; + List> list = new ArrayList<>(); for (MultiBlock mb : multiBlocks) { Map map = new HashMap<>(); diff --git a/src/test/java/fr/openmc/core/features/economy/EconomyFormattingTest.java b/src/test/java/fr/openmc/core/features/economy/EconomyFormattingTest.java new file mode 100644 index 000000000..c0443cd71 --- /dev/null +++ b/src/test/java/fr/openmc/core/features/economy/EconomyFormattingTest.java @@ -0,0 +1,66 @@ +package fr.openmc.core.features.economy; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Locale; + +class EconomyFormattingTest { + + @BeforeAll + static void setUpLocale() { + Locale.setDefault(Locale.US); + } + + @Test + @DisplayName("Format zero balance") + void testFormat_Zero() { + Assertions.assertEquals("0", EconomyManager.getFormattedSimplifiedNumber(0)); + } + + @Test + @DisplayName("Format small number without suffix") + void testFormat_SmallNumber() { + Assertions.assertEquals("500", EconomyManager.getFormattedSimplifiedNumber(500)); + } + + @Test + @DisplayName("Format thousands with k suffix") + void testFormat_Thousands() { + String result = EconomyManager.getFormattedSimplifiedNumber(1500); + Assertions.assertEquals("1.5k", result); + } + + @Test + @DisplayName("Format exact thousand") + void testFormat_ExactThousand() { + Assertions.assertEquals("1k", EconomyManager.getFormattedSimplifiedNumber(1000)); + } + + @Test + @DisplayName("Format millions with M suffix") + void testFormat_Millions() { + Assertions.assertEquals("3M", EconomyManager.getFormattedSimplifiedNumber(3_000_000)); + } + + @Test + @DisplayName("Format billions with B suffix") + void testFormat_Billions() { + Assertions.assertEquals("1B", EconomyManager.getFormattedSimplifiedNumber(1_000_000_000)); + } + + @Test + @DisplayName("Format with decimal truncation") + void testFormat_Decimal() { + String result = EconomyManager.getFormattedSimplifiedNumber(2_500_000); + Assertions.assertEquals("2.5M", result); + } + + @Test + @DisplayName("Format number under 1000") + void testFormat_Under1000() { + Assertions.assertEquals("999", EconomyManager.getFormattedSimplifiedNumber(999)); + } +} diff --git a/src/test/java/fr/openmc/core/features/economy/EconomyManagerTest.java b/src/test/java/fr/openmc/core/features/economy/EconomyManagerTest.java index 5675f2650..a9ddcfb13 100644 --- a/src/test/java/fr/openmc/core/features/economy/EconomyManagerTest.java +++ b/src/test/java/fr/openmc/core/features/economy/EconomyManagerTest.java @@ -75,7 +75,7 @@ public void testSetBalance() { @Test public void testAddBalanceWithReasonRegistersTransaction() { EconomyManager.addBalance(player1.getUniqueId(), 100.0, "Test Reason"); - server.getScheduler().performTicks(20L); + server.getScheduler().waitAsyncTasksFinished(); List transactions = TransactionsManager.getTransactionsByPlayers(player1.getUniqueId()); boolean found = transactions.stream().anyMatch(t -> @@ -91,11 +91,11 @@ public void testAddBalanceWithReasonRegistersTransaction() { public void testWithdrawBalanceWithReasonRegistersTransaction() { EconomyManager.setBalance(player1.getUniqueId(), 200.0); EconomyManager.withdrawBalance(player1.getUniqueId(), 50.0, "Withdrawal Reason"); - server.getScheduler().performTicks(20L); + server.getScheduler().waitAsyncTasksFinished(); List transactions = TransactionsManager.getTransactionsByPlayers(player1.getUniqueId()); - boolean found = transactions.stream().anyMatch(t -> + boolean found = transactions.stream().anyMatch(t -> t.sender.equals(player1.getUniqueId().toString()) && t.amount == 50.0 && t.reason.equals("Withdrawal Reason") @@ -108,10 +108,10 @@ public void testWithdrawBalanceWithReasonRegistersTransaction() { public void testWithdrawBalanceWithoutReasonDoesNotRegisterTransaction() { EconomyManager.setBalance(player1.getUniqueId(), 200.0); EconomyManager.withdrawBalance(player1.getUniqueId(), 50.0); - server.getScheduler().performTicks(20L); + server.getScheduler().waitAsyncTasksFinished(); List transactions = TransactionsManager.getTransactionsByPlayers(player1.getUniqueId()); - boolean found = transactions.stream().anyMatch(t -> + boolean found = transactions.stream().anyMatch(t -> t.sender.equals(player1.getUniqueId().toString()) && t.amount == 50.0 ); @@ -145,7 +145,7 @@ public void testFailedTransferBalanceDueToInsufficientFunds() { public void testTransferBalanceWithReasonRegistersTransaction() { EconomyManager.setBalance(player1.getUniqueId(), 400.0); EconomyManager.transferBalance(player1.getUniqueId(), player2.getUniqueId(), 150.0, "Gift"); - server.getScheduler().performTicks(120L); + server.getScheduler().waitAsyncTasksFinished(); List transactions = TransactionsManager.getTransactionsByPlayers(player1.getUniqueId()); diff --git a/src/test/java/fr/openmc/core/utils/ColorUtilsTest.java b/src/test/java/fr/openmc/core/utils/ColorUtilsTest.java new file mode 100644 index 000000000..da0958d96 --- /dev/null +++ b/src/test/java/fr/openmc/core/utils/ColorUtilsTest.java @@ -0,0 +1,78 @@ +package fr.openmc.core.utils; + +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Material; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class ColorUtilsTest { + + @Test + @DisplayName("getNamedTextColor valid color") + void testGetNamedTextColor_Valid() { + Assertions.assertEquals(NamedTextColor.RED, ColorUtils.getNamedTextColor("red")); + Assertions.assertEquals(NamedTextColor.BLUE, ColorUtils.getNamedTextColor("blue")); + Assertions.assertEquals(NamedTextColor.GREEN, ColorUtils.getNamedTextColor("green")); + } + + @Test + @DisplayName("getNamedTextColor null returns WHITE") + void testGetNamedTextColor_Null() { + Assertions.assertEquals(NamedTextColor.WHITE, ColorUtils.getNamedTextColor(null)); + } + + @Test + @DisplayName("getNamedTextColor invalid returns WHITE") + void testGetNamedTextColor_Invalid() { + Assertions.assertEquals(NamedTextColor.WHITE, ColorUtils.getNamedTextColor("not_a_color")); + } + + @Test + @DisplayName("getColorCode returns correct codes") + void testGetColorCode() { + Assertions.assertEquals("§c", ColorUtils.getColorCode(NamedTextColor.RED)); + Assertions.assertEquals("§a", ColorUtils.getColorCode(NamedTextColor.GREEN)); + Assertions.assertEquals("§9", ColorUtils.getColorCode(NamedTextColor.BLUE)); + Assertions.assertEquals("§f", ColorUtils.getColorCode(NamedTextColor.WHITE)); + Assertions.assertEquals("§0", ColorUtils.getColorCode(NamedTextColor.BLACK)); + } + + @Test + @DisplayName("getNameFromColor returns French names") + void testGetNameFromColor() { + Assertions.assertEquals("§cRouge", ColorUtils.getNameFromColor(NamedTextColor.RED)); + Assertions.assertEquals("§fBlanc", ColorUtils.getNameFromColor(NamedTextColor.WHITE)); + Assertions.assertEquals("§6Orange", ColorUtils.getNameFromColor(NamedTextColor.GOLD)); + } + + @Test + @DisplayName("getMaterialFromColor returns correct wool") + void testGetMaterialFromColor() { + Assertions.assertEquals(Material.RED_WOOL, ColorUtils.getMaterialFromColor(NamedTextColor.RED)); + Assertions.assertEquals(Material.WHITE_WOOL, ColorUtils.getMaterialFromColor(NamedTextColor.WHITE)); + Assertions.assertEquals(Material.BLACK_WOOL, ColorUtils.getMaterialFromColor(NamedTextColor.BLACK)); + } + + @Test + @DisplayName("getReadableColor maps correctly") + void testGetReadableColor() { + Assertions.assertEquals(NamedTextColor.DARK_GRAY, ColorUtils.getReadableColor(NamedTextColor.BLACK)); + Assertions.assertEquals(NamedTextColor.GRAY, ColorUtils.getReadableColor(NamedTextColor.WHITE)); + Assertions.assertEquals(NamedTextColor.GOLD, ColorUtils.getReadableColor(NamedTextColor.YELLOW)); + Assertions.assertEquals(NamedTextColor.RED, ColorUtils.getReadableColor(NamedTextColor.RED)); + } + + @Test + @DisplayName("getRGBFromNamedTextColor returns correct RGB") + void testGetRGBFromNamedTextColor() { + int[] red = ColorUtils.getRGBFromNamedTextColor(NamedTextColor.RED); + Assertions.assertArrayEquals(new int[]{255, 85, 85}, red); + + int[] black = ColorUtils.getRGBFromNamedTextColor(NamedTextColor.BLACK); + Assertions.assertArrayEquals(new int[]{0, 0, 0}, black); + + int[] white = ColorUtils.getRGBFromNamedTextColor(NamedTextColor.WHITE); + Assertions.assertArrayEquals(new int[]{255, 255, 255}, white); + } +} diff --git a/src/test/java/fr/openmc/core/utils/DateUtilsTest.java b/src/test/java/fr/openmc/core/utils/DateUtilsTest.java index 3d3ef954a..865ea00a4 100644 --- a/src/test/java/fr/openmc/core/utils/DateUtilsTest.java +++ b/src/test/java/fr/openmc/core/utils/DateUtilsTest.java @@ -9,10 +9,84 @@ class DateUtilsTest { @Test @DisplayName("Time to Ticks") void testConvertTime() { - Assertions.assertEquals( - "20m", - DateUtils.convertTime(24000) - ); + Assertions.assertEquals("20m", DateUtils.convertTime(24000)); } -} \ No newline at end of file + @Test + @DisplayName("Convert 0 seconds") + void testConvertSecondToTime_Zero() { + Assertions.assertEquals("0s", DateUtils.convertSecondToTime(0)); + } + + @Test + @DisplayName("Convert seconds only") + void testConvertSecondToTime_SecondsOnly() { + Assertions.assertEquals("45s", DateUtils.convertSecondToTime(45)); + } + + @Test + @DisplayName("Convert minutes and seconds") + void testConvertSecondToTime_MinutesAndSeconds() { + Assertions.assertEquals("2m 30s", DateUtils.convertSecondToTime(150)); + } + + @Test + @DisplayName("Convert hours, minutes and seconds") + void testConvertSecondToTime_HoursMinutesSeconds() { + Assertions.assertEquals("1h 5m 10s", DateUtils.convertSecondToTime(3910)); + } + + @Test + @DisplayName("Convert days, hours, minutes and seconds") + void testConvertSecondToTime_Full() { + Assertions.assertEquals("3j 4h 2m 38s", DateUtils.convertSecondToTime(273758)); + } + + @Test + @DisplayName("Convert exact hours") + void testConvertSecondToTime_ExactHours() { + Assertions.assertEquals("2h", DateUtils.convertSecondToTime(7200)); + } + + @Test + @DisplayName("Convert millis to time") + void testConvertMillisToTime() { + Assertions.assertEquals("1m 30s", DateUtils.convertMillisToTime(90000)); + } + + @Test + @DisplayName("Convert 0 millis") + void testConvertMillisToTime_Zero() { + Assertions.assertEquals("0s", DateUtils.convertMillisToTime(0)); + } + + @Test + @DisplayName("isBefore - same year, earlier week") + void testIsBefore_SameYearEarlierWeek() { + Assertions.assertTrue(DateUtils.isBefore("2025-10", "2025-20")); + } + + @Test + @DisplayName("isBefore - same year, same week") + void testIsBefore_SameWeek() { + Assertions.assertTrue(DateUtils.isBefore("2025-10", "2025-10")); + } + + @Test + @DisplayName("isBefore - same year, later week") + void testIsBefore_SameYearLaterWeek() { + Assertions.assertFalse(DateUtils.isBefore("2025-20", "2025-10")); + } + + @Test + @DisplayName("isBefore - earlier year") + void testIsBefore_EarlierYear() { + Assertions.assertTrue(DateUtils.isBefore("2024-50", "2025-1")); + } + + @Test + @DisplayName("isBefore - later year") + void testIsBefore_LaterYear() { + Assertions.assertFalse(DateUtils.isBefore("2026-1", "2025-50")); + } +} diff --git a/src/test/java/fr/openmc/core/utils/EnumUtilsTest.java b/src/test/java/fr/openmc/core/utils/EnumUtilsTest.java new file mode 100644 index 000000000..499489e03 --- /dev/null +++ b/src/test/java/fr/openmc/core/utils/EnumUtilsTest.java @@ -0,0 +1,47 @@ +package fr.openmc.core.utils; + +import org.bukkit.Material; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class EnumUtilsTest { + + @Test + @DisplayName("Match valid enum value") + void testMatch_Valid() { + Assertions.assertEquals(Material.STONE, EnumUtils.match("stone", Material.class)); + } + + @Test + @DisplayName("Match valid enum value case insensitive") + void testMatch_CaseInsensitive() { + Assertions.assertEquals(Material.DIAMOND, EnumUtils.match("diamond", Material.class)); + Assertions.assertEquals(Material.DIAMOND, EnumUtils.match("DIAMOND", Material.class)); + Assertions.assertEquals(Material.DIAMOND, EnumUtils.match("Diamond", Material.class)); + } + + @Test + @DisplayName("Match invalid key returns null") + void testMatch_InvalidReturnsNull() { + Assertions.assertNull(EnumUtils.match("not_a_material", Material.class)); + } + + @Test + @DisplayName("Match invalid key returns default value") + void testMatch_InvalidReturnsDefault() { + Assertions.assertEquals(Material.AIR, EnumUtils.match("not_a_material", Material.class, Material.AIR)); + } + + @Test + @DisplayName("Match null key returns default") + void testMatch_NullKey() { + Assertions.assertEquals(Material.STONE, EnumUtils.match(null, Material.class, Material.STONE)); + } + + @Test + @DisplayName("Match null key returns null without default") + void testMatch_NullKeyNoDefault() { + Assertions.assertNull(EnumUtils.match(null, Material.class)); + } +} diff --git a/src/test/java/fr/openmc/core/utils/InputUtilsTest.java b/src/test/java/fr/openmc/core/utils/InputUtilsTest.java index e72417864..a399df5f3 100644 --- a/src/test/java/fr/openmc/core/utils/InputUtilsTest.java +++ b/src/test/java/fr/openmc/core/utils/InputUtilsTest.java @@ -11,51 +11,79 @@ class InputUtilsTest { @Test @DisplayName("Conversion Sign Input to Money") void testConvertSignInputToMoney_ShouldGiveTheAmountInFloat() { - Assertions.assertEquals( - 3000000.0, - InputUtils.convertToMoneyValue("3m") - ); - Assertions.assertEquals( - 3000.0, - InputUtils.convertToMoneyValue("3k") - ); - Assertions.assertEquals( - 3000000.0, - InputUtils.convertToMoneyValue("3M") - ); - Assertions.assertEquals( - 3000.0, - InputUtils.convertToMoneyValue("3K") - ); - Assertions.assertEquals( - 1.0, - InputUtils.convertToMoneyValue("1") - ); - Assertions.assertEquals( - 3000.0, - InputUtils.convertToMoneyValue("3000") - ); + Assertions.assertEquals(3000000.0, InputUtils.convertToMoneyValue("3m")); + Assertions.assertEquals(3000.0, InputUtils.convertToMoneyValue("3k")); + Assertions.assertEquals(3000000.0, InputUtils.convertToMoneyValue("3M")); + Assertions.assertEquals(3000.0, InputUtils.convertToMoneyValue("3K")); + Assertions.assertEquals(1.0, InputUtils.convertToMoneyValue("1")); + Assertions.assertEquals(3000.0, InputUtils.convertToMoneyValue("3000")); + } + + @Test + @DisplayName("Conversion with decimals") + void testConvertToMoneyValue_Decimals() { + Assertions.assertEquals(2500000.0, InputUtils.convertToMoneyValue("2.5m")); + Assertions.assertEquals(1500.0, InputUtils.convertToMoneyValue("1.5k")); + Assertions.assertEquals(99.99, InputUtils.convertToMoneyValue("99.99")); } @ParameterizedTest @DisplayName("Conversion of input sign to -1") - @ValueSource(strings = {"-3", "-1", "489y", "4,5"}) + @ValueSource(strings = {"-3", "-1", "489y", "4,5", "NaN", "Infinity", "-Infinity"}) void testConvertSignInputToMoney_ShouldGiveAnError(String input) { Assertions.assertEquals(-1, InputUtils.convertToMoneyValue(input)); } + @Test + @DisplayName("Conversion null and empty returns -1") + void testConvertToMoneyValue_NullAndEmpty() { + Assertions.assertEquals(-1, InputUtils.convertToMoneyValue(null)); + Assertions.assertEquals(-1, InputUtils.convertToMoneyValue("")); + } + @ParameterizedTest @DisplayName("Check is returned value is true") - @ValueSource(strings = {"1", "3m", "3k", "3M", "3K", "3000"}) + @ValueSource(strings = {"1", "3m", "3k", "3M", "3K", "3000", "2.5m", "0.5k"}) void testIsInputMoney_MustReturnTrue(String input) { Assertions.assertTrue(InputUtils.isInputMoney(input)); } @ParameterizedTest @DisplayName("Check is returned value is false") - @ValueSource(strings = {"0", "-3", "-1", "489y", "4,5"}) + @ValueSource(strings = {"0", "-3", "-1", "489y", "4,5", "NaN", "Infinity", "-Infinity"}) void testIsInputMoney_MustReturnFalse(String input) { Assertions.assertFalse(InputUtils.isInputMoney(input)); } + @Test + @DisplayName("isInputMoney null and empty") + void testIsInputMoney_NullAndEmpty() { + Assertions.assertFalse(InputUtils.isInputMoney(null)); + Assertions.assertFalse(InputUtils.isInputMoney("")); + } + + @Test + @DisplayName("Pluralize with count > 1 adds s") + void testPluralize_Plural() { + Assertions.assertEquals("joueurs", InputUtils.pluralize("joueur", 5)); + } + + @Test + @DisplayName("Pluralize with count 1 no s") + void testPluralize_Singular() { + Assertions.assertEquals("joueur", InputUtils.pluralize("joueur", 1)); + } + + @Test + @DisplayName("Pluralize with count 0 no s") + void testPluralize_Zero() { + Assertions.assertEquals("joueur", InputUtils.pluralize("joueur", 0)); + } + + @Test + @DisplayName("Pluralize long variant") + void testPluralize_Long() { + Assertions.assertEquals("blocs", InputUtils.pluralize("bloc", 100L)); + Assertions.assertEquals("bloc", InputUtils.pluralize("bloc", 1L)); + } } diff --git a/src/test/java/fr/openmc/core/utils/MathUtilsTest.java b/src/test/java/fr/openmc/core/utils/MathUtilsTest.java new file mode 100644 index 000000000..0453bcb0e --- /dev/null +++ b/src/test/java/fr/openmc/core/utils/MathUtilsTest.java @@ -0,0 +1,52 @@ +package fr.openmc.core.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class MathUtilsTest { + + @Test + @DisplayName("lerpColor t=0 returns start color") + void testLerpColor_Start() { + int start = 0xFF0000; + int end = 0x0000FF; + Assertions.assertEquals(start, MathUtils.lerpColor(start, end, 0.0)); + } + + @Test + @DisplayName("lerpColor t=1 returns end color") + void testLerpColor_End() { + int start = 0xFF0000; + int end = 0x0000FF; + Assertions.assertEquals(end, MathUtils.lerpColor(start, end, 1.0)); + } + + @Test + @DisplayName("lerpColor t=0.5 returns midpoint") + void testLerpColor_Midpoint() { + int start = 0x000000; + int end = 0xFEFEFE; + int result = MathUtils.lerpColor(start, end, 0.5); + Assertions.assertEquals(0x7F7F7F, result); + } + + @Test + @DisplayName("lerpColor same colors returns same") + void testLerpColor_SameColors() { + int color = 0xABCDEF; + Assertions.assertEquals(color, MathUtils.lerpColor(color, color, 0.5)); + } + + @Test + @DisplayName("lerpColor black to white at 0.25") + void testLerpColor_QuarterWay() { + int result = MathUtils.lerpColor(0x000000, 0xFFFFFF, 0.25); + int r = (result >> 16) & 0xFF; + int g = (result >> 8) & 0xFF; + int b = result & 0xFF; + Assertions.assertEquals(63, r); + Assertions.assertEquals(63, g); + Assertions.assertEquals(63, b); + } +} diff --git a/src/test/java/fr/openmc/core/utils/MotdUtilsTest.java b/src/test/java/fr/openmc/core/utils/MotdUtilsTest.java index b6902cf2d..8449ae767 100644 --- a/src/test/java/fr/openmc/core/utils/MotdUtilsTest.java +++ b/src/test/java/fr/openmc/core/utils/MotdUtilsTest.java @@ -31,9 +31,9 @@ private String getComponentContent(Component component) { @Test @DisplayName("MOTD switch") void testMOTD() { + server.motd(Component.text("default")); String motd = getComponentContent(server.motd()); - new MotdUtils(); server.getScheduler().performTicks(12001L); Assertions.assertNotEquals(getComponentContent(server.motd()), motd); diff --git a/src/test/java/fr/openmc/core/utils/PaddingUtilsTest.java b/src/test/java/fr/openmc/core/utils/PaddingUtilsTest.java new file mode 100644 index 000000000..14639345b --- /dev/null +++ b/src/test/java/fr/openmc/core/utils/PaddingUtilsTest.java @@ -0,0 +1,46 @@ +package fr.openmc.core.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class PaddingUtilsTest { + + @Test + @DisplayName("Center text in given width") + void testFormat_Centered() { + String result = PaddingUtils.format("hi", 10); + Assertions.assertEquals(10, result.length()); + Assertions.assertEquals(" hi ", result); + } + + @Test + @DisplayName("Text longer than width returns text without extra padding") + void testFormat_TextLongerThanWidth() { + String result = PaddingUtils.format("hello world", 5); + Assertions.assertEquals("hello world", result); + } + + @Test + @DisplayName("Text exactly equals width") + void testFormat_ExactWidth() { + String result = PaddingUtils.format("abcde", 5); + Assertions.assertEquals("abcde", result); + } + + @Test + @DisplayName("Odd padding distributes correctly") + void testFormat_OddPadding() { + String result = PaddingUtils.format("ab", 5); + Assertions.assertEquals(5, result.length()); + Assertions.assertEquals(" ab ", result); + } + + @Test + @DisplayName("Empty string gets full padding") + void testFormat_EmptyString() { + String result = PaddingUtils.format("", 4); + Assertions.assertEquals(4, result.length()); + Assertions.assertEquals(" ", result); + } +} diff --git a/src/test/java/fr/openmc/core/utils/QueueTest.java b/src/test/java/fr/openmc/core/utils/QueueTest.java new file mode 100644 index 000000000..e00c1764d --- /dev/null +++ b/src/test/java/fr/openmc/core/utils/QueueTest.java @@ -0,0 +1,78 @@ +package fr.openmc.core.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class QueueTest { + + @Test + @DisplayName("Add and get element") + void testAddAndGet() { + Queue queue = new Queue<>(5); + queue.add("a", 1); + Assertions.assertEquals(1, queue.get("a")); + } + + @Test + @DisplayName("Remove element") + void testRemove() { + Queue queue = new Queue<>(5); + queue.add("a", 1); + queue.remove("a"); + Assertions.assertNull(queue.get("a")); + } + + @Test + @DisplayName("Get non-existent key returns null") + void testGet_NonExistent() { + Queue queue = new Queue<>(5); + Assertions.assertNull(queue.get("missing")); + } + + @Test + @DisplayName("Eviction when exceeding size") + void testEviction() { + Queue queue = new Queue<>(3); + queue.add("a", 1); + queue.add("b", 2); + queue.add("c", 3); + queue.add("d", 4); + + Assertions.assertNull(queue.get("a")); + Assertions.assertEquals(2, queue.get("b")); + Assertions.assertEquals(3, queue.get("c")); + Assertions.assertEquals(4, queue.get("d")); + } + + @Test + @DisplayName("Queue respects max size") + void testMaxSize() { + Queue queue = new Queue<>(2); + queue.add(1, "one"); + queue.add(2, "two"); + queue.add(3, "three"); + + Assertions.assertEquals(2, queue.getQueue().size()); + } + + @Test + @DisplayName("Overwrite existing key") + void testOverwrite() { + Queue queue = new Queue<>(5); + queue.add("a", 1); + queue.add("a", 99); + Assertions.assertEquals(99, queue.get("a")); + } + + @Test + @DisplayName("Queue size 1 keeps only last element") + void testSizeOne() { + Queue queue = new Queue<>(1); + queue.add("first", "1"); + queue.add("second", "2"); + + Assertions.assertNull(queue.get("first")); + Assertions.assertEquals("2", queue.get("second")); + } +} diff --git a/src/test/java/fr/openmc/core/utils/RandomUtilsTest.java b/src/test/java/fr/openmc/core/utils/RandomUtilsTest.java new file mode 100644 index 000000000..29c74d7bb --- /dev/null +++ b/src/test/java/fr/openmc/core/utils/RandomUtilsTest.java @@ -0,0 +1,47 @@ +package fr.openmc.core.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.RepeatedTest; +import org.junit.jupiter.api.Test; + +class RandomUtilsTest { + + @RepeatedTest(50) + @DisplayName("randomBetween int stays in bounds") + void testRandomBetweenInt_InBounds() { + int result = RandomUtils.randomBetween(5, 10); + Assertions.assertTrue(result >= 5 && result <= 10, + "Expected between 5 and 10, got: " + result); + } + + @RepeatedTest(50) + @DisplayName("randomBetween double stays in bounds") + void testRandomBetweenDouble_InBounds() { + double result = RandomUtils.randomBetween(1.0, 5.0); + Assertions.assertTrue(result >= 1.0 && result < 5.0, + "Expected between 1.0 and 5.0, got: " + result); + } + + @RepeatedTest(50) + @DisplayName("randomBetween float stays in bounds") + void testRandomBetweenFloat_InBounds() { + float result = RandomUtils.randomBetween(0.0f, 1.0f); + Assertions.assertTrue(result >= 0.0f && result < 1.0f, + "Expected between 0.0 and 1.0, got: " + result); + } + + @Test + @DisplayName("randomBetween int same min max returns that value") + void testRandomBetweenInt_SameMinMax() { + Assertions.assertEquals(7, RandomUtils.randomBetween(7, 7)); + } + + @RepeatedTest(50) + @DisplayName("randomBetween int negative range") + void testRandomBetweenInt_NegativeRange() { + int result = RandomUtils.randomBetween(-10, -5); + Assertions.assertTrue(result >= -10 && result <= -5, + "Expected between -10 and -5, got: " + result); + } +} diff --git a/src/test/java/fr/openmc/core/utils/YmlUtilsTest.java b/src/test/java/fr/openmc/core/utils/YmlUtilsTest.java new file mode 100644 index 000000000..426fcb2a3 --- /dev/null +++ b/src/test/java/fr/openmc/core/utils/YmlUtilsTest.java @@ -0,0 +1,89 @@ +package fr.openmc.core.utils; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +class YmlUtilsTest { + + @Test + @DisplayName("Deep copy simple map") + void testDeepCopy_SimpleMap() { + Map original = new HashMap<>(); + original.put("key1", "value1"); + original.put("key2", 42); + + Map copy = YmlUtils.deepCopy(original); + + Assertions.assertEquals(original, copy); + Assertions.assertNotSame(original, copy); + } + + @Test + @DisplayName("Deep copy nested map") + void testDeepCopy_NestedMap() { + Map inner = new HashMap<>(); + inner.put("nested", "value"); + + Map original = new HashMap<>(); + original.put("outer", inner); + + Map copy = YmlUtils.deepCopy(original); + + Assertions.assertEquals("value", ((Map) copy.get("outer")).get("nested")); + + inner.put("nested", "modified"); + Assertions.assertEquals("value", ((Map) copy.get("outer")).get("nested")); + } + + @Test + @DisplayName("Deep copy with list") + void testDeepCopy_WithList() { + List list = new ArrayList<>(); + list.add("a"); + list.add("b"); + + Map original = new HashMap<>(); + original.put("items", list); + + Map copy = YmlUtils.deepCopy(original); + + list.add("c"); + List copiedList = (List) copy.get("items"); + Assertions.assertEquals(2, copiedList.size()); + } + + @Test + @DisplayName("Deep copy primitives are preserved") + void testDeepCopyObject_Primitives() { + Assertions.assertEquals("hello", YmlUtils.deepCopyObject("hello")); + Assertions.assertEquals(42, YmlUtils.deepCopyObject(42)); + Assertions.assertEquals(3.14, YmlUtils.deepCopyObject(3.14)); + Assertions.assertTrue((Boolean) YmlUtils.deepCopyObject(true)); + } + + @Test + @DisplayName("Deep copy empty map") + void testDeepCopy_EmptyMap() { + Map copy = YmlUtils.deepCopy(new HashMap<>()); + Assertions.assertTrue(copy.isEmpty()); + } + + @Test + @DisplayName("Deep copy null key is skipped") + void testDeepCopy_NullKey() { + Map original = new HashMap<>(); + original.put(null, "value"); + original.put("key", "val"); + + Map copy = YmlUtils.deepCopy(original); + + Assertions.assertFalse(copy.containsKey(null)); + Assertions.assertEquals("val", copy.get("key")); + } +} From 6ecb3bad9794ad13ffd5cd9c903e476e4135750d Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 20 Mar 2026 22:24:44 +0100 Subject: [PATCH 39/52] =?UTF-8?q?Ajout=20des=20d=C3=A9gats=20de=20chute=20?= =?UTF-8?q?dans=20la=20dimension=20(1=20bloc=20tomb=C3=A9=20=3D=20-1.5=20s?= =?UTF-8?q?)=20(#1210)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update v2.5 branch (#1165) * Fix soul chestplate altar crafting * Change SoulAxe rarity from COMMON to RARE * Correctif de la possibilité de se faire de l'argent a l'infini (#1158) * fix: claim dupli * fix: Cannot invoke "String.isEmpty()" because "content" is null * fix: FancyNpcsPlugin is null * fix: incorrect singularity transfer (#1157) * Refonte du principe pour aller dans la dimension des rêves (#1156) * fix: dream sleep (100%) * rework: sleep to dream * impl fall damage * add sound --- .../dream/listeners/dream/PlayerDamageListener.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerDamageListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerDamageListener.java index ddc990ffe..d2ad79d0e 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerDamageListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerDamageListener.java @@ -1,19 +1,27 @@ package fr.openmc.core.features.dream.listeners.dream; import fr.openmc.core.features.dream.DreamUtils; +import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageEvent; public class PlayerDamageListener implements Listener { - @EventHandler public void onFall(EntityDamageEvent event) { if (event.getCause() != EntityDamageEvent.DamageCause.FALL) return; if (!(event.getEntity() instanceof Player player)) return; if (DreamUtils.isInDream(player)) { + double fallDistance = player.getFallDistance(); + if (fallDistance < 5) return; + + long secondsLost = (long) (fallDistance * 1.5); + + DreamUtils.removeDreamTime(player, secondsLost, true); + player.playSound(player.getEyeLocation(), Sound.ENTITY_PLAYER_BIG_FALL, 1f, 1f); + event.setCancelled(true); } } From 53688e60e0212cf9b1709188690818509d2524e9 Mon Sep 17 00:00:00 2001 From: Gtol <162237671+gtolontop@users.noreply.github.com> Date: Sun, 22 Mar 2026 13:24:21 +0100 Subject: [PATCH 40/52] fix: null check sur getPlayerCity() dans calculatePlayerInterest() (#1215) --- src/main/java/fr/openmc/core/features/economy/BankManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/openmc/core/features/economy/BankManager.java b/src/main/java/fr/openmc/core/features/economy/BankManager.java index 0e1240d3c..6086a0850 100644 --- a/src/main/java/fr/openmc/core/features/economy/BankManager.java +++ b/src/main/java/fr/openmc/core/features/economy/BankManager.java @@ -198,7 +198,8 @@ public static double calculatePlayerInterest(UUID playerUUID) { double interest = .01; // base interest is 1% if (MayorManager.phaseMayor == 2) { - if (PerkManager.hasPerk(CityManager.getPlayerCity(playerUUID).getMayor(), Perks.BUSINESS_MAN.getId())) { + City city = CityManager.getPlayerCity(playerUUID); + if (city != null && PerkManager.hasPerk(city.getMayor(), Perks.BUSINESS_MAN.getId())) { interest += .02; // interest is +2% when perk Business Man enabled } } From e7de576530474c0d68ae2fc00be67aeba2a8adf3 Mon Sep 17 00:00:00 2001 From: Gtol <162237671+gtolontop@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:43:05 +0100 Subject: [PATCH 41/52] =?UTF-8?q?fix:=20corriger=20la=20profondeur=20du=20?= =?UTF-8?q?Hammer=20(3x3x3=20=E2=86=92=203x3x2)=20(#1217)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../openmc/core/registry/items/contents/Hammer.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/openmc/core/registry/items/contents/Hammer.java b/src/main/java/fr/openmc/core/registry/items/contents/Hammer.java index ee8fd486f..33bf35dbc 100644 --- a/src/main/java/fr/openmc/core/registry/items/contents/Hammer.java +++ b/src/main/java/fr/openmc/core/registry/items/contents/Hammer.java @@ -36,9 +36,12 @@ private static BlockFace getTargetFace(Player player) { private static Vector rotateOffset(int x, int y, int z, BlockFace face) { return switch (face) { - case NORTH, SOUTH -> new Vector(x, y, z); - case EAST, WEST -> new Vector(z, y, x); - case UP, DOWN -> new Vector(x, z, y); + case SOUTH -> new Vector(x, y, z); + case NORTH -> new Vector(x, y, -z); + case EAST -> new Vector(z, y, x); + case WEST -> new Vector(-z, y, x); + case UP -> new Vector(x, z, y); + case DOWN -> new Vector(x, -z, y); default -> new Vector(0, 0, 0); }; } @@ -51,7 +54,7 @@ private void breakArea(Player player, Block origin, BlockFace face, ItemStack to for (int dx = -radius; dx <= radius; dx++) { for (int dy = -radius; dy <= radius; dy++) { - for (int dz = -depth; dz <= depth; dz++) { + for (int dz = 0; dz <= depth; dz++) { if (dx == 0 && dy == 0 && dz == 0) continue; From 77ebb67b6c4a1caceeaf57a3421ea42fe0b0b2f3 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:54:04 +0100 Subject: [PATCH 42/52] Changement sur le Cube (stop command, une bulle = un cube) (#1227) * one particuleTask for each Cube * add stop command * finalize * orthograf --- .../fr/openmc/core/features/cube/Cube.java | 60 +++++++++++-------- .../core/features/cube/CubeCommands.java | 35 +++++++++++ .../core/features/cube/ReproductionTask.java | 4 ++ .../core/features/friend/FriendCommand.java | 2 +- 4 files changed, 74 insertions(+), 27 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/cube/Cube.java b/src/main/java/fr/openmc/core/features/cube/Cube.java index 53b00c9c4..c53661271 100644 --- a/src/main/java/fr/openmc/core/features/cube/Cube.java +++ b/src/main/java/fr/openmc/core/features/cube/Cube.java @@ -25,6 +25,8 @@ // - iambibi_ public class Cube extends MultiBlock { public BukkitTask corruptedBubbleTask; + public BukkitTask particuleBubbleTask; + public ReproductionTask reproductionTask; public BossBar cubeBossBar; public boolean showBossBar; @@ -199,15 +201,17 @@ public void startMagneticShock() { } } - public final int RADIUS_BUBBLE = this.radius * 3; + public final int RADIUS_BUBBLE = this.radius * 4; public void startCorruptedBubble() { Location center = this.getCenter(); - int totalTicks = 20 * 3600; + int totalTicks = 20 * 1300; startBubbleParticles(); + if (corruptedBubbleTask != null) corruptedBubbleTask.cancel(); + int intervalCorruption = 20 * 15; corruptedBubbleTask = new BukkitRunnable() { int elapsed = 0; @@ -231,7 +235,7 @@ public void run() { if (isPartOf(new Location(origin.getWorld(), x, y, z))) continue; - Location loc = center.clone().add(x, y, z); + Location loc = center.add(x, y, z); Block block = loc.getBlock(); Material type = block.getType(); @@ -264,31 +268,36 @@ public void startBubbleParticles() { Location center = this.getCenter(); double radius = RADIUS_BUBBLE; - Bukkit.getScheduler().runTaskTimer(OMCPlugin.getInstance(), () -> { - for (int i = 0; i < 50; i++) { - double theta = Math.random() * 2 * Math.PI; - double phi = Math.random() * Math.PI; - double x = radius * Math.sin(phi) * Math.cos(theta); - double y = radius * Math.cos(phi); - double z = radius * Math.sin(phi) * Math.sin(theta); + if (particuleBubbleTask != null) particuleBubbleTask.cancel(); - Location particleLoc = center.clone().add(x, y, z); - world.spawnParticle(Particle.OMINOUS_SPAWNING, particleLoc, 1, 0.1, 0.1, 0.1, 0); - } - - for (double theta = 0; theta < Math.PI; theta += Math.PI / 16) { - for (double phi = 0; phi < 2 * Math.PI; phi += Math.PI / 16) { - double x = radius * Math.sin(theta) * Math.cos(phi); - double y = radius * Math.cos(theta); - double z = radius * Math.sin(theta) * Math.sin(phi); + particuleBubbleTask = new BukkitRunnable() { + @Override + public void run() { + for (int i = 0; i < 50; i++) { + double theta = Math.random() * 2 * Math.PI; + double phi = Math.random() * Math.PI; + double x = radius * Math.sin(phi) * Math.cos(theta); + double y = radius * Math.cos(phi); + double z = radius * Math.sin(phi) * Math.sin(theta); Location particleLoc = center.clone().add(x, y, z); + world.spawnParticle(Particle.OMINOUS_SPAWNING, particleLoc, 1, 0.1, 0.1, 0.1, 0); + } - Vector dir = center.clone().subtract(particleLoc).toVector().normalize(); - world.spawnParticle(Particle.SNEEZE, particleLoc, 1, dir.getX(), dir.getY(), dir.getZ(), 0.1); + for (double theta = 0; theta < Math.PI; theta += Math.PI / 16) { + for (double phi = 0; phi < 2 * Math.PI; phi += Math.PI / 16) { + double x = radius * Math.sin(theta) * Math.cos(phi); + double y = radius * Math.cos(theta); + double z = radius * Math.sin(theta) * Math.sin(phi); + + Location particleLoc = center.clone().add(x, y, z); + + Vector dir = center.clone().subtract(particleLoc).toVector().normalize(); + world.spawnParticle(Particle.SNEEZE, particleLoc, 1, dir.getX(), dir.getY(), dir.getZ(), 0.1); + } } } - }, 0L, 20L); + }.runTaskTimer(OMCPlugin.getInstance(), 0L, 20L); } public void startReproduction() { @@ -345,14 +354,13 @@ public void startEventsCycle() { public void run() { double roll = ThreadLocalRandom.current().nextDouble(); - if (roll < 0.5) { + if (roll < 0.7) { startMagneticShock(); } else { - if (corruptedBubbleTask == null) - startCorruptedBubble(); + startCorruptedBubble(); } } - }.runTaskTimer(OMCPlugin.getInstance(), 20L * 60 * 5, 20L * 60 * 20); + }.runTaskTimer(OMCPlugin.getInstance(), 20L * 60 * 5, 20L * 60 * 10); } public void startSoundCycle() { diff --git a/src/main/java/fr/openmc/core/features/cube/CubeCommands.java b/src/main/java/fr/openmc/core/features/cube/CubeCommands.java index 5fcd49b89..0167c6619 100644 --- a/src/main/java/fr/openmc/core/features/cube/CubeCommands.java +++ b/src/main/java/fr/openmc/core/features/cube/CubeCommands.java @@ -47,6 +47,41 @@ public void startCorruptedBubble( MessagesManager.sendMessage(player, Component.text("Bulle corrompue lancé"), Prefix.STAFF, MessageType.SUCCESS, false); } + @Subcommand("stopShock") + @CommandPermission("omc.admins.commands.cube.shock") + public void stopShock( + Player player, + @Named("cubeLoc") @SuggestWith(CubeLocationAutoComplete.class) String cubeLoc + ) { + Cube cube = getInputCubes(player, cubeLoc); + + if (cube == null) return; + + MessagesManager.sendMessage(player, Component.text("Choc éléctro-magnétique arreté"), Prefix.STAFF, MessageType.SUCCESS, false); + } + + @Subcommand("stopBubble") + @CommandPermission("omc.admins.commands.cube.bubble") + public void stopCorruptedBubble( + Player player, + @Named("cubeLoc") @SuggestWith(CubeLocationAutoComplete.class) String cubeLoc + ) { + Cube cube = getInputCubes(player, cubeLoc); + + if (cube == null) return; + + if (cube.particuleBubbleTask != null) { + cube.particuleBubbleTask.cancel(); + cube.particuleBubbleTask = null; + } + + if (cube.corruptedBubbleTask != null) { + cube.corruptedBubbleTask.cancel(); + cube.corruptedBubbleTask = null; + } + MessagesManager.sendMessage(player, Component.text("Bulle corrompue arreté"), Prefix.STAFF, MessageType.SUCCESS, false); + } + @Subcommand("reproduce") @CommandPermission("omc.admins.commands.cube.reproduce") public void reproduceCube( diff --git a/src/main/java/fr/openmc/core/features/cube/ReproductionTask.java b/src/main/java/fr/openmc/core/features/cube/ReproductionTask.java index 7845cd234..0b392ff0b 100644 --- a/src/main/java/fr/openmc/core/features/cube/ReproductionTask.java +++ b/src/main/java/fr/openmc/core/features/cube/ReproductionTask.java @@ -40,6 +40,10 @@ public void run() { world.playSound(babyOrigin, Sound.ENTITY_ENDER_DRAGON_GROWL, 0.3f, 0.2f); world.spawnParticle(Particle.EXPLOSION_EMITTER, babyCube.getCenter(), 3, 1, 1, 1, 0); + for (int i = 0; i <= 10; i++) { + world.strikeLightningEffect(babyCube.getCenter()); + } + MultiBlockManager.register(babyCube); cancel(); parent.reproductionTask = null; diff --git a/src/main/java/fr/openmc/core/features/friend/FriendCommand.java b/src/main/java/fr/openmc/core/features/friend/FriendCommand.java index 6256f50c4..903d7683a 100644 --- a/src/main/java/fr/openmc/core/features/friend/FriendCommand.java +++ b/src/main/java/fr/openmc/core/features/friend/FriendCommand.java @@ -164,7 +164,7 @@ public void listCommand( .color(isOnline ? NamedTextColor.GREEN : NamedTextColor.YELLOW) .decoration(TextDecoration.BOLD, isOnline)) .hoverEvent(HoverEvent.showText( - Component.text("§7Vile : §e" + (city != null ? city.getName() : "Aucune") + + Component.text("§7Ville : §e" + (city != null ? city.getName() : "Aucune") + "\n§7Argent : §e" + formattedMoney + "\n§7Statut : " + (isOnline ? "§aEn ligne" : "§cHors ligne") ))) From 976a49360ee3e2519b27fad85ed4f8f22eaf7ccf Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:55:53 +0100 Subject: [PATCH 43/52] Correction sur le bouton de retour (#1228) * texte long https://github.com/ServerOpenMC/PluginV2/issues/1223 * fix back button --- src/main/java/fr/openmc/api/menulib/MenuLib.java | 5 +++++ .../milestones/tutorial/quests/HomeUpgradeQuest.java | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/fr/openmc/api/menulib/MenuLib.java b/src/main/java/fr/openmc/api/menulib/MenuLib.java index 8a9ad6f78..503da8c01 100644 --- a/src/main/java/fr/openmc/api/menulib/MenuLib.java +++ b/src/main/java/fr/openmc/api/menulib/MenuLib.java @@ -218,6 +218,11 @@ public void onClose(InventoryCloseEvent e) { if (!(e.getPlayer() instanceof Player player)) return; if (e.getInventory().getHolder(false) instanceof PaginatedMenu paginatedMenu) { paginatedMenu.onClose(e); + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { + if (!(e.getPlayer().getOpenInventory().getTopInventory().getHolder() instanceof PaginatedMenu)) { + MenuLib.clearHistory(player); + } + }, 1L); return; } diff --git a/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/HomeUpgradeQuest.java b/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/HomeUpgradeQuest.java index d6dbf1740..f0c0bbe20 100644 --- a/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/HomeUpgradeQuest.java +++ b/src/main/java/fr/openmc/core/features/milestones/tutorial/quests/HomeUpgradeQuest.java @@ -23,7 +23,8 @@ public HomeUpgradeQuest() { super( "Améliorer votre limite de homes", List.of( - "§fTapez §d/upgradehome §fou bien aller dans le §dmenu des homes (/homes) §fpour pouvoir améliorer votre limite de homes", + "§fTapez §d/upgradehome §fou bien aller dans le §dmenu des homes (/homes)", + "§fpour pouvoir améliorer votre limite de homes", "§8§oCela vous permettra d'avoir plus de homes !" ), CustomItemRegistry.getByName("omc_homes:omc_homes_icon_upgrade").getBest(), From 33cf86f2454bf7cd1eb051bc82d3c60514e364c0 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 27 Mar 2026 21:35:22 +0100 Subject: [PATCH 44/52] try fix: corruption --- src/main/java/fr/openmc/core/features/cube/Cube.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/openmc/core/features/cube/Cube.java b/src/main/java/fr/openmc/core/features/cube/Cube.java index c53661271..d15d4ac9d 100644 --- a/src/main/java/fr/openmc/core/features/cube/Cube.java +++ b/src/main/java/fr/openmc/core/features/cube/Cube.java @@ -235,7 +235,7 @@ public void run() { if (isPartOf(new Location(origin.getWorld(), x, y, z))) continue; - Location loc = center.add(x, y, z); + Location loc = center.clone().add(x, y, z); Block block = loc.getBlock(); Material type = block.getType(); From 4ab4d453ff7b7c0a562e6c3144f76f7b7d16e90f Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sun, 29 Mar 2026 14:54:04 +0200 Subject: [PATCH 45/52] fix CLEAR TABLE WHEN SERVER CRASH... (#1239) --- .../fr/openmc/core/features/homes/HomesManager.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/fr/openmc/core/features/homes/HomesManager.java b/src/main/java/fr/openmc/core/features/homes/HomesManager.java index d3fbb5bce..3d0921222 100644 --- a/src/main/java/fr/openmc/core/features/homes/HomesManager.java +++ b/src/main/java/fr/openmc/core/features/homes/HomesManager.java @@ -5,6 +5,7 @@ import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; import fr.openmc.core.CommandsManager; +import fr.openmc.core.OMCPlugin; import fr.openmc.core.features.homes.command.*; import fr.openmc.core.features.homes.models.Home; import fr.openmc.core.features.homes.models.HomeLimit; @@ -21,6 +22,8 @@ @Getter public class HomesManager { + private static boolean isInitialized = false; + public static final List homes = new ArrayList<>(); public static final List homeLimits = new ArrayList<>(); @@ -39,6 +42,8 @@ public static void init() { loadHomeLimit(); loadHomes(); + + isInitialized = true; } public static void saveHomesData() { @@ -130,6 +135,10 @@ private static void loadHomeLimit() { } private static void saveHomeLimit() { + if (!isInitialized) { + OMCPlugin.getInstance().getSLF4JLogger().warn("Tentative de sauvegarde des HomeLimits avant l'initialisation du manager, opération ignorée."); + return; + } try { TableUtils.clearTable(DatabaseManager.getConnectionSource(), HomeLimit.class); limitsDao.create(homeLimits); @@ -147,6 +156,10 @@ private static void loadHomes() { } private static void saveHomes() { + if (!isInitialized) { + OMCPlugin.getInstance().getSLF4JLogger().warn("Tentative de sauvegarde des Homes avant l'initialisation du manager, opération ignorée."); + return; + } try { TableUtils.clearTable(DatabaseManager.getConnectionSource(), Home.class); for (Home home : homes) { From 495bc4809614fd991d56ad8e6fc3912405b5edf0 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sun, 5 Apr 2026 12:10:40 +0200 Subject: [PATCH 46/52] =?UTF-8?q?Correctif=20des=20creepers=20qui=20explos?= =?UTF-8?q?ait=20les=20entit=C3=A9s=20murales=20(item=20frame,=20painting)?= =?UTF-8?q?=20dans=20les=20claims=20(#1237)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../listeners/protections/HangingProtection.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/city/listeners/protections/HangingProtection.java b/src/main/java/fr/openmc/core/features/city/listeners/protections/HangingProtection.java index 8b4c82f4f..a2b185cde 100644 --- a/src/main/java/fr/openmc/core/features/city/listeners/protections/HangingProtection.java +++ b/src/main/java/fr/openmc/core/features/city/listeners/protections/HangingProtection.java @@ -7,6 +7,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.hanging.HangingBreakByEntityEvent; +import org.bukkit.event.hanging.HangingBreakEvent; import org.bukkit.event.player.PlayerInteractEntityEvent; public class HangingProtection implements Listener { @@ -22,8 +23,18 @@ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { @EventHandler(ignoreCancelled = true) public void onHangingBreakByEntity(HangingBreakByEntityEvent event) { - if (event.getRemover() instanceof Player player) { - ProtectionsManager.verify(player, event, event.getEntity().getLocation()); + Entity remover = event.getRemover(); + if (remover != null) { + ProtectionsManager.verify(remover, event, event.getEntity().getLocation()); + } + } + + @EventHandler(ignoreCancelled = true) + public void onHangingBreak(HangingBreakEvent event) { + if (event.getCause() == HangingBreakEvent.RemoveCause.EXPLOSION) { + if (!ProtectionsManager.canExplodeNaturally(event.getEntity().getLocation())) { + event.setCancelled(true); + } } } } From 46489fc7518dc26dec07e7bdb5bf83eb3ebf19e1 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sun, 5 Apr 2026 12:12:19 +0200 Subject: [PATCH 47/52] =?UTF-8?q?Ajout=20d'info=20suppl=C3=A9mentaire=20po?= =?UTF-8?q?ur=20la=20qu=C3=AAte=20de=20Casser=20des=20Buches=20(#1236)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/quests/menus/QuestsMenu.java | 1 + .../core/features/quests/objects/Quest.java | 7 ++ .../features/quests/quests/BreakLogQuest.java | 77 ++++++++++++------- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/quests/menus/QuestsMenu.java b/src/main/java/fr/openmc/core/features/quests/menus/QuestsMenu.java index ab5e90d70..d56a576c7 100644 --- a/src/main/java/fr/openmc/core/features/quests/menus/QuestsMenu.java +++ b/src/main/java/fr/openmc/core/features/quests/menus/QuestsMenu.java @@ -260,6 +260,7 @@ else if (isCompleted) quest.getDescription(playerUUID).forEach(string -> { lore.add(Component.text(" §f" + string)); }); + lore.addAll(quest.getAdditionalLore()); if (currentTier.getSteps() != null && !currentTier.getSteps().isEmpty()) { lore.add(Component.empty()); lore.add(Component.text("§6◆ §eAvancement:")); diff --git a/src/main/java/fr/openmc/core/features/quests/objects/Quest.java b/src/main/java/fr/openmc/core/features/quests/objects/Quest.java index 9d6861400..e38f616cf 100644 --- a/src/main/java/fr/openmc/core/features/quests/objects/Quest.java +++ b/src/main/java/fr/openmc/core/features/quests/objects/Quest.java @@ -10,6 +10,7 @@ import fr.openmc.core.utils.messages.MessagesManager; import fr.openmc.core.utils.messages.Prefix; import lombok.Getter; +import lombok.Setter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; @@ -31,6 +32,8 @@ public class Quest { private final String name; private final List baseDescription; + @Setter + private List additionalLore; private final ItemStack icon; private final boolean isLargeActionBar; private final List tiers = new ArrayList<>(); @@ -50,6 +53,7 @@ public class Quest { public Quest(String name, List baseDescription, ItemStack icon) { this.name = name; this.baseDescription = baseDescription; + this.additionalLore = List.of(); this.icon = icon; this.isLargeActionBar = false; } @@ -64,6 +68,7 @@ public Quest(String name, List baseDescription, ItemStack icon) { public Quest(String name, List baseDescription, Material icon) { this.name = name; this.baseDescription = baseDescription; + this.additionalLore = List.of(); this.icon = new ItemStack(icon); this.isLargeActionBar = false; } @@ -79,6 +84,7 @@ public Quest(String name, List baseDescription, Material icon) { public Quest(String name, List baseDescription, ItemStack icon, boolean isLargeActionBar) { this.name = name; this.baseDescription = baseDescription; + this.additionalLore = List.of(); this.icon = icon; this.isLargeActionBar = isLargeActionBar; } @@ -94,6 +100,7 @@ public Quest(String name, List baseDescription, ItemStack icon, boolean public Quest(String name, List baseDescription, Material icon, boolean isLargeActionBar) { this.name = name; this.baseDescription = baseDescription; + this.additionalLore = List.of(); this.icon = new ItemStack(icon); this.isLargeActionBar = isLargeActionBar; } diff --git a/src/main/java/fr/openmc/core/features/quests/quests/BreakLogQuest.java b/src/main/java/fr/openmc/core/features/quests/quests/BreakLogQuest.java index ac6106c0a..1334b7854 100644 --- a/src/main/java/fr/openmc/core/features/quests/quests/BreakLogQuest.java +++ b/src/main/java/fr/openmc/core/features/quests/quests/BreakLogQuest.java @@ -4,6 +4,10 @@ import fr.openmc.core.features.quests.objects.QuestTier; import fr.openmc.core.features.quests.rewards.QuestItemReward; import fr.openmc.core.features.quests.rewards.QuestMoneyReward; +import fr.openmc.core.utils.ItemUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.enchantments.Enchantment; @@ -13,33 +17,49 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; import java.util.EnumMap; import java.util.List; import java.util.Map; public class BreakLogQuest extends Quest implements Listener { - private final Map logWeights = new EnumMap<>(Material.class); - - /** - * Crée une hâche enchantée pour les récompenses. - * @param material Le matériau de la hache (ex: Material.IRON_AXE) - * @return ItemStack enchanté - */ - private ItemStack getEnchantedAxe(Material material) { - ItemStack axe = ItemStack.of(material); - axe.editMeta(meta -> { - meta.addEnchant(Enchantment.EFFICIENCY, 3, true); // Efficacité III - meta.addEnchant(Enchantment.UNBREAKING, 2, true); // Solidité II - }); - return axe; + private final static Map logWeights = new EnumMap<>(Material.class); + static { + // Définir les poids (progression plus rapide pour les bûches rares) + logWeights.put(Material.OAK_LOG, 1); + logWeights.put(Material.BIRCH_LOG, 1); + logWeights.put(Material.SPRUCE_LOG, 1); + logWeights.put(Material.ACACIA_LOG, 2); + logWeights.put(Material.DARK_OAK_LOG, 3); + logWeights.put(Material.JUNGLE_LOG, 3); + logWeights.put(Material.MANGROVE_LOG, 4); + logWeights.put(Material.CHERRY_LOG, 4); + logWeights.put(Material.CRIMSON_STEM, 5); + logWeights.put(Material.WARPED_STEM, 5); } + private static List getLore() { + List lore = new ArrayList<>(); + + for (var entry : logWeights.entrySet()) { + lore.add(Component.text("- ").color(NamedTextColor.DARK_GRAY) + .append(ItemUtils.getItemTranslation(entry.getKey())) + .append(Component.text(" : ")) + .append(Component.text(entry.getValue()).color(NamedTextColor.AQUA)) + .append(Component.text(" points")) + .decoration(TextDecoration.ITALIC, false) + .color(NamedTextColor.GRAY) + ); + } + + return lore; + } public BreakLogQuest() { super("Bûcheron de l'extrême", List.of("Casser {target} bûches"), new ItemStack(Material.IRON_AXE)); - + this.setAdditionalLore(getLore()); this.addTiers( new QuestTier(500, new QuestMoneyReward(300), new QuestItemReward(Material.IRON_AXE, 1)), new QuestTier(1500, new QuestMoneyReward(500), new QuestItemReward(getEnchantedAxe(Material.IRON_AXE), 1)), @@ -47,19 +67,6 @@ public BreakLogQuest() { new QuestTier(15000, new QuestMoneyReward(3000), new QuestItemReward(getEnchantedAxe(Material.DIAMOND_AXE), 1)) ); - - - // Définir les poids (progression plus rapide pour les bûches rares) - logWeights.put(Material.OAK_LOG, 1); - logWeights.put(Material.BIRCH_LOG, 1); - logWeights.put(Material.SPRUCE_LOG, 1); - logWeights.put(Material.ACACIA_LOG, 2); - logWeights.put(Material.DARK_OAK_LOG, 3); - logWeights.put(Material.JUNGLE_LOG, 3); - logWeights.put(Material.MANGROVE_LOG, 4); - logWeights.put(Material.CHERRY_LOG, 4); - logWeights.put(Material.CRIMSON_STEM, 5); - logWeights.put(Material.WARPED_STEM, 5); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -72,4 +79,18 @@ public void onPlayerBreak(BlockBreakEvent event) { this.incrementProgress(event.getPlayer().getUniqueId(), progress); } } + + /** + * Crée une hâche enchantée pour les récompenses. + * @param material Le matériau de la hache (ex: Material.IRON_AXE) + * @return ItemStack enchanté + */ + private ItemStack getEnchantedAxe(Material material) { + ItemStack axe = ItemStack.of(material); + axe.editMeta(meta -> { + meta.addEnchant(Enchantment.EFFICIENCY, 3, true); // Efficacité III + meta.addEnchant(Enchantment.UNBREAKING, 2, true); // Solidité II + }); + return axe; + } } From dad5caf3e5cd0756c3c27f89195aef8396838c93 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sun, 5 Apr 2026 12:13:19 +0200 Subject: [PATCH 48/52] =?UTF-8?q?Simplifier=20la=20cr=C3=A9ation=20de=20me?= =?UTF-8?q?ssages=20pour=20le=20chat=20en=20async=20(#1235)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fr/openmc/core/listeners/AsyncChatListener.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/openmc/core/listeners/AsyncChatListener.java b/src/main/java/fr/openmc/core/listeners/AsyncChatListener.java index db9b57aca..655dbe4c3 100644 --- a/src/main/java/fr/openmc/core/listeners/AsyncChatListener.java +++ b/src/main/java/fr/openmc/core/listeners/AsyncChatListener.java @@ -1,11 +1,12 @@ package fr.openmc.core.listeners; -import fr.openmc.core.OMCPlugin; import fr.openmc.api.hooks.LuckPermsHook; +import fr.openmc.core.OMCPlugin; import io.papermc.paper.event.player.AsyncChatEvent; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.format.TextColor; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.luckperms.api.LuckPerms; import net.luckperms.api.cacheddata.CachedMetaData; import org.bukkit.Bukkit; @@ -33,16 +34,17 @@ public void onChat(AsyncChatEvent event) { final Player player = event.getPlayer(); final CachedMetaData metaData = this.luckperms.getPlayerAdapter(Player.class).getMetaData(player); - String message = ((TextComponent) event.message()).content(); + String message = PlainTextComponentSerializer.plainText().serialize(event.message()); String rawMessage = plugin.getConfig().getString("chat.message", "{prefix}{name}§7: {message}") .replace("{prefix}", LuckPermsHook.getFormattedPAPIPrefix(player)) .replace("{suffix}", metaData.getSuffix() != null ? metaData.getSuffix() : "") .replace("{name}", player.getName()) .replace("{message}", message); - final String formattedMessage = colorize(translateHexColorCodes(rawMessage)); + final Component formattedMessage = LegacyComponentSerializer.legacySection() + .deserialize(colorize(translateHexColorCodes(rawMessage))); - event.renderer((source, sourceDisplayName, component, viewer) -> Component.text(formattedMessage)); + event.renderer((source, sourceDisplayName, component, viewer) -> formattedMessage); for (Player p : Bukkit.getOnlinePlayers()) { if (message.contains(p.getName())) From a339ec1c450d0aadc9957fbdf59a913779b8b6b9 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sun, 5 Apr 2026 12:14:14 +0200 Subject: [PATCH 49/52] =?UTF-8?q?Correction=20des=20effets=20qui=20n'?= =?UTF-8?q?=C3=A9tait=20pas=20correctement=20enlever=20avec=20les=20armure?= =?UTF-8?q?s=20(#1234)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/listeners/EquipableItemListener.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/openmc/core/listeners/EquipableItemListener.java b/src/main/java/fr/openmc/core/listeners/EquipableItemListener.java index 913c8ae96..9b67bcb06 100644 --- a/src/main/java/fr/openmc/core/listeners/EquipableItemListener.java +++ b/src/main/java/fr/openmc/core/listeners/EquipableItemListener.java @@ -3,12 +3,9 @@ import fr.openmc.core.OMCPlugin; import fr.openmc.core.events.ArmorEquipEvent; import fr.openmc.core.features.dream.DreamUtils; -import fr.openmc.core.features.dream.registries.DreamItemRegistry; import fr.openmc.core.registry.items.CustomItem; import fr.openmc.core.registry.items.CustomItemRegistry; import fr.openmc.core.registry.items.options.EquipableItem; -import fr.openmc.core.utils.ArmorType; -import fr.openmc.core.utils.ItemUtils; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -20,11 +17,12 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class EquipableItemListener implements Listener { + private final Map> appliedEffectsByPlayer = new HashMap<>(); + @EventHandler public void onEquip(ArmorEquipEvent event) { if (event.getType() == null) return; @@ -57,6 +55,8 @@ public void onQuit(PlayerQuitEvent event) { equipable.removeEffects(player); } } + + appliedEffectsByPlayer.remove(player.getUniqueId()); } @EventHandler @@ -76,6 +76,15 @@ public void onDreamTeleport(PlayerTeleportEvent event) { } private void recalc(Player player, ItemStack oldPiece) { + UUID playerId = player.getUniqueId(); + + Set previouslyApplied = appliedEffectsByPlayer.get(playerId); + if (previouslyApplied != null) { + for (PotionEffectType type : previouslyApplied) { + player.removePotionEffect(type); + } + } + if (oldPiece != null && !oldPiece.getType().isAir()) { CustomItem customItem = CustomItemRegistry.getByItemStack(oldPiece); @@ -101,6 +110,8 @@ private void recalc(Player player, ItemStack oldPiece) { } } + Set newApplied = new HashSet<>(); + for (var entry : effects.entrySet()) { PotionEffectType type = entry.getKey(); int amplifier = entry.getValue(); @@ -115,6 +126,10 @@ private void recalc(Player player, ItemStack oldPiece) { true ) ); + + newApplied.add(type); } + + appliedEffectsByPlayer.put(playerId, newApplied); } } \ No newline at end of file From 4f41c7b793e04f0342fd8ee93bd269470518746d Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sun, 5 Apr 2026 12:16:21 +0200 Subject: [PATCH 50/52] =?UTF-8?q?Correction=20de=20la=20camera=20bug=C3=A9?= =?UTF-8?q?e=20du=20a=20l'emote=20de=20join=20+=20Setting=20+=20Invincibil?= =?UTF-8?q?it=C3=A9=20(#1233)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * try to fix the bug when playEmote add a error * add settings for JOIN_ANIMATION + invulnerable while animation * review iambibi invulnerable --- .../animations/listeners/EmoteListener.java | 2 ++ .../listeners/PlayerFinishJoiningListener.java | 16 ++++++++++++++-- .../core/features/settings/SettingType.java | 4 +++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/animations/listeners/EmoteListener.java b/src/main/java/fr/openmc/core/features/animations/listeners/EmoteListener.java index acfc15fca..2fe3241c6 100644 --- a/src/main/java/fr/openmc/core/features/animations/listeners/EmoteListener.java +++ b/src/main/java/fr/openmc/core/features/animations/listeners/EmoteListener.java @@ -96,6 +96,8 @@ private void animationEnd(Player player) { PlayerAnimationInfo info = playingAnimations.remove(player); if (info == null) return; + player.setInvulnerable(false); + sendCamera(player, player); if (info.getArmorStand() != null) info.getArmorStand().remove(); diff --git a/src/main/java/fr/openmc/core/features/animations/listeners/PlayerFinishJoiningListener.java b/src/main/java/fr/openmc/core/features/animations/listeners/PlayerFinishJoiningListener.java index dc40d728a..78ad65def 100644 --- a/src/main/java/fr/openmc/core/features/animations/listeners/PlayerFinishJoiningListener.java +++ b/src/main/java/fr/openmc/core/features/animations/listeners/PlayerFinishJoiningListener.java @@ -4,6 +4,8 @@ import fr.openmc.core.OMCPlugin; import fr.openmc.core.features.animations.Animation; import fr.openmc.core.features.animations.PlayerAnimationInfo; +import fr.openmc.core.features.settings.PlayerSettingsManager; +import fr.openmc.core.features.settings.SettingType; import org.bukkit.GameMode; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -19,16 +21,26 @@ public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); boolean onGround = player.getLocation().subtract(0, 1, 0).getBlock().getType().isSolid(); + if (!(boolean) PlayerSettingsManager.getPlayerSettings(player.getUniqueId()).getSetting(SettingType.JOIN_ANIMATION)) return; if (player.isFlying() || !onGround || player.getGameMode().equals(GameMode.SPECTATOR)) return; playingAnimations.put(player, new PlayerAnimationInfo()); EmoteListener.setupHead(player); + player.setInvulnerable(true); new BukkitRunnable() { @Override public void run() { - player.playSound(player, "omc_sounds:ambient.join_rift", 1.0f, 1.0f); - CustomPlayer.playEmote(player, Animation.JOIN_RIFT.getNameAnimation()); + if (!player.isOnline()) return; + + player.getWorld().playSound(player.getLocation(), "omc_sounds:ambient.join_rift", 1.0f, 1.0f); + try { + CustomPlayer.playEmote(player, Animation.JOIN_RIFT.getNameAnimation()); + } catch (Exception e) { + playingAnimations.remove(player); + EmoteListener.sendCamera(player, player); + player.setInvulnerable(false); + } } }.runTaskLater(OMCPlugin.getInstance(), 11L); } diff --git a/src/main/java/fr/openmc/core/features/settings/SettingType.java b/src/main/java/fr/openmc/core/features/settings/SettingType.java index cc24a9530..fdad9ccc6 100644 --- a/src/main/java/fr/openmc/core/features/settings/SettingType.java +++ b/src/main/java/fr/openmc/core/features/settings/SettingType.java @@ -32,7 +32,9 @@ public enum SettingType { Material.NOTE_BLOCK, Material.GRAY_DYE, "Activer ou désactiver les sons des messages privés"), TELEPORT_TITLE_FADE(ValueType.BOOLEAN, true, "Fondu du titre lors des téléportations", Material.ENDER_PEARL, Material.GRAY_DYE, "Activer ou désactiver le fondu du titre lors des téléportations"), - + JOIN_ANIMATION(ValueType.BOOLEAN, true, "Animation de connexion", + Material.GLOW_INK_SAC, Material.INK_SAC, "Activer ou désactiver l'animation de connexion"), + ; private final ValueType valueType; From 703ca3ee3926ffd3d9f7710503b64844aa82fe54 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sun, 5 Apr 2026 13:19:33 +0200 Subject: [PATCH 51/52] =?UTF-8?q?Ajout=20d'une=20base=20pour=20les=20?= =?UTF-8?q?=C3=A9venements=20de=20week=20end=20(rotation=20entre=20les=20e?= =?UTF-8?q?vents,=20calendrier)=20(#1221)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rewrite contest system launch + add WeeklyEvent for more flexibility * Rewrite contest schedule + gestion for multiple events * fix init * add CalendarMenu and /events --- .../java/fr/openmc/core/CommandsManager.java | 6 +- src/main/java/fr/openmc/core/OMCPlugin.java | 6 +- .../city/sub/notation/NotationManager.java | 2 +- .../scoreboards/sb/MainScoreboard.java | 37 +-- .../events/commands/EventCommand.java | 18 ++ .../halloween/commands/HalloweenCommands.java | 4 +- .../listeners/HalloweenNPCListener.java | 4 +- .../halloween/managers/HalloweenManager.java | 6 +- .../menus/HalloweenPumpkinDepositMenu.java | 4 +- .../halloween/models/HalloweenData.java | 2 +- .../weeklyevents/WeeklyEventsManager.java | 260 ++++++++++++++++++ .../contents/contest/Contest.java | 38 +++ .../contents/contest/ContestPhase.java | 125 +++++++++ .../contest/commands/ContestCommand.java | 106 +++---- .../ColorContestAutoComplete.java | 4 +- .../ContestPhaseAutoComplete.java | 20 ++ .../TradeContestAutoComplete.java | 4 +- .../contest/events}/ContestEndEvent.java | 8 +- .../listeners/ContestIntractEvents.java | 2 +- .../contest/managers/ContestManager.java | 106 ++----- .../managers/ContestPlayerManager.java | 4 +- .../contest/managers/TradeYMLManager.java | 10 +- .../contest/menu/ContributionMenu.java | 6 +- .../contents}/contest/menu/MoreInfoMenu.java | 12 +- .../contents}/contest/menu/TradeMenu.java | 8 +- .../contents}/contest/menu/VoteMenu.java | 6 +- .../contents/contest/models/ContestData.java} | 25 +- .../contest/models/ContestPlayer.java | 2 +- .../weeklyevents/models/WeeklyEvent.java | 35 +++ .../weeklyevents/models/WeeklyEventPhase.java | 15 + .../weeklyevents/models/WeeklyEventsData.java | 33 +++ .../events/managers/CalendarManager.java | 92 +++++++ .../features/events/menus/CalendarMenu.java | 130 +++++++++ .../core/features/events/models/Event.java | 13 + .../leaderboards/LeaderboardManager.java | 4 +- .../core/features/mainmenu/menus/Page1.java | 15 +- .../quests/quests/WinContestQuest.java | 2 +- .../java/fr/openmc/core/utils/DateUtils.java | 4 +- .../fr/openmc/core/utils/ParticleUtils.java | 11 +- .../core/utils/database/DatabaseManager.java | 6 +- 40 files changed, 961 insertions(+), 234 deletions(-) create mode 100644 src/main/java/fr/openmc/core/features/events/commands/EventCommand.java rename src/main/java/fr/openmc/core/features/events/{ => contents}/halloween/commands/HalloweenCommands.java (70%) rename src/main/java/fr/openmc/core/features/events/{ => contents}/halloween/listeners/HalloweenNPCListener.java (80%) rename src/main/java/fr/openmc/core/features/events/{ => contents}/halloween/managers/HalloweenManager.java (97%) rename src/main/java/fr/openmc/core/features/events/{ => contents}/halloween/menus/HalloweenPumpkinDepositMenu.java (96%) rename src/main/java/fr/openmc/core/features/events/{ => contents}/halloween/models/HalloweenData.java (90%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/weeklyevents/WeeklyEventsManager.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/Contest.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/ContestPhase.java rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/commands/ContestCommand.java (54%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/commands/autocomplete/ColorContestAutoComplete.java (71%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/ContestPhaseAutoComplete.java rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/commands/autocomplete/TradeContestAutoComplete.java (71%) rename src/main/java/fr/openmc/core/features/{contest => events/contents/weeklyevents/contents/contest/events}/ContestEndEvent.java (82%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/listeners/ContestIntractEvents.java (88%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/managers/ContestManager.java (87%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/managers/ContestPlayerManager.java (97%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/managers/TradeYMLManager.java (96%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/menu/ContributionMenu.java (96%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/menu/MoreInfoMenu.java (86%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/menu/TradeMenu.java (96%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/menu/VoteMenu.java (97%) rename src/main/java/fr/openmc/core/features/{contest/models/Contest.java => events/contents/weeklyevents/contents/contest/models/ContestData.java} (83%) rename src/main/java/fr/openmc/core/features/{ => events/contents/weeklyevents/contents}/contest/models/ContestPlayer.java (92%) create mode 100644 src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEvent.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEventPhase.java create mode 100644 src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEventsData.java create mode 100644 src/main/java/fr/openmc/core/features/events/managers/CalendarManager.java create mode 100644 src/main/java/fr/openmc/core/features/events/menus/CalendarMenu.java create mode 100644 src/main/java/fr/openmc/core/features/events/models/Event.java diff --git a/src/main/java/fr/openmc/core/CommandsManager.java b/src/main/java/fr/openmc/core/CommandsManager.java index b37c8dc49..3af0c9e03 100644 --- a/src/main/java/fr/openmc/core/CommandsManager.java +++ b/src/main/java/fr/openmc/core/CommandsManager.java @@ -11,7 +11,8 @@ import fr.openmc.core.features.animations.DebugAnimationCommand; import fr.openmc.core.features.credits.CreditsCommand; import fr.openmc.core.features.cube.CubeCommands; -import fr.openmc.core.features.events.halloween.commands.HalloweenCommands; +import fr.openmc.core.features.events.commands.EventCommand; +import fr.openmc.core.features.events.contents.halloween.commands.HalloweenCommands; import fr.openmc.core.features.friend.FriendCommand; import fr.openmc.core.features.mailboxes.MailboxCommand; import fr.openmc.core.features.mainmenu.commands.MainMenuCommand; @@ -61,7 +62,8 @@ private static void registerCommands() { new CreditsCommand(), new CubeCommands(), new HalloweenCommands(), - new DebugAnimationCommand() + new DebugAnimationCommand(), + new EventCommand() ); } } diff --git a/src/main/java/fr/openmc/core/OMCPlugin.java b/src/main/java/fr/openmc/core/OMCPlugin.java index 30d956fca..c731d53a4 100644 --- a/src/main/java/fr/openmc/core/OMCPlugin.java +++ b/src/main/java/fr/openmc/core/OMCPlugin.java @@ -15,7 +15,6 @@ import fr.openmc.core.features.city.sub.notation.NotationManager; import fr.openmc.core.features.city.sub.statistics.CityStatisticsManager; import fr.openmc.core.features.city.sub.war.WarManager; -import fr.openmc.core.features.contest.managers.ContestManager; import fr.openmc.core.features.cube.multiblocks.MultiBlockManager; import fr.openmc.core.features.displays.TabList; import fr.openmc.core.features.displays.bossbar.BossbarManager; @@ -25,7 +24,9 @@ import fr.openmc.core.features.dream.generation.DreamDimensionManager; import fr.openmc.core.features.economy.BankManager; import fr.openmc.core.features.economy.EconomyManager; -import fr.openmc.core.features.events.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; import fr.openmc.core.features.homes.HomesManager; import fr.openmc.core.features.homes.icons.HomeIconCacheManager; import fr.openmc.core.features.leaderboards.LeaderboardManager; @@ -161,6 +162,7 @@ public void loadWithItemsAdder() { QuestsManager.init(); CityManager.init(); ContestManager.init(); + WeeklyEventsManager.init(); DreamManager.init(); MultiBlockManager.init(); if (WorldGuardHook.isHasWorldGuard()) { diff --git a/src/main/java/fr/openmc/core/features/city/sub/notation/NotationManager.java b/src/main/java/fr/openmc/core/features/city/sub/notation/NotationManager.java index 5f9db1242..a4fff03a2 100644 --- a/src/main/java/fr/openmc/core/features/city/sub/notation/NotationManager.java +++ b/src/main/java/fr/openmc/core/features/city/sub/notation/NotationManager.java @@ -338,7 +338,7 @@ public static void giveReward(String weekStr) { * Planifie l'exécution de la tâche de minuit qui calcule les scores et attribue les récompenses. */ private static void scheduleMidnightTask() { - long delayInTicks = DateUtils.getSecondsUntilDayOfWeekMidnight(APPLY_NOTATION_DAY) * 20; + long delayInTicks = DateUtils.getSecondsUntilDayOfWeekTime(APPLY_NOTATION_DAY, 0, 0, 0) * 20; Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { if (!isApplied) { String weekStr = DateUtils.getWeekFormat(); diff --git a/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java b/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java index 92d08fca7..81e835944 100644 --- a/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java +++ b/src/main/java/fr/openmc/core/features/displays/scoreboards/sb/MainScoreboard.java @@ -9,11 +9,14 @@ import fr.openmc.api.scoreboard.SternalBoard; import fr.openmc.core.features.city.City; import fr.openmc.core.features.city.CityManager; -import fr.openmc.core.features.contest.managers.ContestManager; -import fr.openmc.core.features.contest.models.Contest; import fr.openmc.core.features.displays.scoreboards.BaseScoreboard; import fr.openmc.core.features.economy.EconomyManager; -import fr.openmc.core.features.events.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.Contest; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestPhase; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models.ContestData; import fr.openmc.core.utils.DateUtils; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -40,19 +43,21 @@ public void update(Player player, SternalBoard board) { List lines = new ArrayList<>(getDefaultLines(player)); // Contest - Contest data = ContestManager.data; - if (data.getPhase() != 1) { - lines.add(MiniMessage.miniMessage().deserialize("%s".formatted(textToSmall("contest"))).decoration(TextDecoration.BOLD, true)); - lines.add(text(" • ", NamedTextColor.DARK_GRAY) - .append(text(textToSmall(data.getCamp1()), data.getColor1AsNamedTextColor())) - .append(text(textToSmall(" VS "), NamedTextColor.GRAY)) - .append(text(textToSmall(data.getCamp2()), data.getColor2AsNamedTextColor())) - ); - lines.add(Component.text(" • ", NamedTextColor.DARK_GRAY) - .append(Component.text(textToSmall("fin:"), NamedTextColor.GRAY)) - .appendSpace() - .append(text(DateUtils.getTimeUntilNextDay(DayOfWeek.MONDAY), TextColor.color(0xFF8F06))) - ); + if (WeeklyEventsManager.getCurrentEvent() instanceof Contest) { + ContestData data = ContestManager.data; + if (WeeklyEventsManager.getCurrentPhase() != ContestPhase.VOTE_CAMP.getPhase()) { + lines.add(MiniMessage.miniMessage().deserialize("%s".formatted(textToSmall("contest"))).decoration(TextDecoration.BOLD, true)); + lines.add(text(" • ", NamedTextColor.DARK_GRAY) + .append(text(textToSmall(data.getCamp1()), data.getColor1AsNamedTextColor())) + .append(text(textToSmall(" VS "), NamedTextColor.GRAY)) + .append(text(textToSmall(data.getCamp2()), data.getColor2AsNamedTextColor())) + ); + lines.add(Component.text(" • ", NamedTextColor.DARK_GRAY) + .append(Component.text(textToSmall("fin:"), NamedTextColor.GRAY)) + .appendSpace() + .append(text(DateUtils.getTimeUntilNextDay(DayOfWeek.MONDAY), TextColor.color(0xFF8F06))) + ); + } } lines.add(empty()); diff --git a/src/main/java/fr/openmc/core/features/events/commands/EventCommand.java b/src/main/java/fr/openmc/core/features/events/commands/EventCommand.java new file mode 100644 index 000000000..2248a2155 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/commands/EventCommand.java @@ -0,0 +1,18 @@ +package fr.openmc.core.features.events.commands; + +import fr.openmc.core.features.events.menus.CalendarMenu; +import org.bukkit.entity.Player; +import revxrsal.commands.annotation.Command; +import revxrsal.commands.annotation.CommandPlaceholder; +import revxrsal.commands.annotation.Cooldown; +import revxrsal.commands.annotation.Description; + +@Command("events") +@Description("Ouvre l'interface des événement (journalier et weekly") +public class EventCommand { + @Cooldown(2) + @CommandPlaceholder() + public static void mainCommand(Player player) { + new CalendarMenu(player).open(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/halloween/commands/HalloweenCommands.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/commands/HalloweenCommands.java similarity index 70% rename from src/main/java/fr/openmc/core/features/events/halloween/commands/HalloweenCommands.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/commands/HalloweenCommands.java index 549b56a71..11bde75c0 100644 --- a/src/main/java/fr/openmc/core/features/events/halloween/commands/HalloweenCommands.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/commands/HalloweenCommands.java @@ -1,6 +1,6 @@ -package fr.openmc.core.features.events.halloween.commands; +package fr.openmc.core.features.events.contents.halloween.commands; -import fr.openmc.core.features.events.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; import revxrsal.commands.annotation.Command; import revxrsal.commands.annotation.Subcommand; import revxrsal.commands.bukkit.annotation.CommandPermission; diff --git a/src/main/java/fr/openmc/core/features/events/halloween/listeners/HalloweenNPCListener.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/listeners/HalloweenNPCListener.java similarity index 80% rename from src/main/java/fr/openmc/core/features/events/halloween/listeners/HalloweenNPCListener.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/listeners/HalloweenNPCListener.java index 9c5943936..f5a7c3c83 100644 --- a/src/main/java/fr/openmc/core/features/events/halloween/listeners/HalloweenNPCListener.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/listeners/HalloweenNPCListener.java @@ -1,7 +1,7 @@ -package fr.openmc.core.features.events.halloween.listeners; +package fr.openmc.core.features.events.contents.halloween.listeners; import de.oliver.fancynpcs.api.events.NpcInteractEvent; -import fr.openmc.core.features.events.halloween.menus.HalloweenPumpkinDepositMenu; +import fr.openmc.core.features.events.contents.halloween.menus.HalloweenPumpkinDepositMenu; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; diff --git a/src/main/java/fr/openmc/core/features/events/halloween/managers/HalloweenManager.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/managers/HalloweenManager.java similarity index 97% rename from src/main/java/fr/openmc/core/features/events/halloween/managers/HalloweenManager.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/managers/HalloweenManager.java index bfbf96700..f845ebf68 100644 --- a/src/main/java/fr/openmc/core/features/events/halloween/managers/HalloweenManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/managers/HalloweenManager.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.events.halloween.managers; +package fr.openmc.core.features.events.contents.halloween.managers; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; @@ -10,8 +10,8 @@ import fr.openmc.api.hooks.FancyNpcsHook; import fr.openmc.core.OMCPlugin; import fr.openmc.core.features.economy.EconomyManager; -import fr.openmc.core.features.events.halloween.listeners.HalloweenNPCListener; -import fr.openmc.core.features.events.halloween.models.HalloweenData; +import fr.openmc.core.features.events.contents.halloween.listeners.HalloweenNPCListener; +import fr.openmc.core.features.events.contents.halloween.models.HalloweenData; import fr.openmc.core.features.leaderboards.LeaderboardManager; import fr.openmc.core.features.mailboxes.MailboxManager; import fr.openmc.core.registry.items.CustomItemRegistry; diff --git a/src/main/java/fr/openmc/core/features/events/halloween/menus/HalloweenPumpkinDepositMenu.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/menus/HalloweenPumpkinDepositMenu.java similarity index 96% rename from src/main/java/fr/openmc/core/features/events/halloween/menus/HalloweenPumpkinDepositMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/menus/HalloweenPumpkinDepositMenu.java index d2c0142a1..6b25b72c1 100644 --- a/src/main/java/fr/openmc/core/features/events/halloween/menus/HalloweenPumpkinDepositMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/menus/HalloweenPumpkinDepositMenu.java @@ -1,9 +1,9 @@ -package fr.openmc.core.features.events.halloween.menus; +package fr.openmc.core.features.events.contents.halloween.menus; import fr.openmc.api.menulib.Menu; import fr.openmc.api.menulib.utils.InventorySize; import fr.openmc.api.menulib.utils.ItemBuilder; -import fr.openmc.core.features.events.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; import fr.openmc.core.utils.ItemUtils; import fr.openmc.core.utils.messages.MessageType; import fr.openmc.core.utils.messages.MessagesManager; diff --git a/src/main/java/fr/openmc/core/features/events/halloween/models/HalloweenData.java b/src/main/java/fr/openmc/core/features/events/contents/halloween/models/HalloweenData.java similarity index 90% rename from src/main/java/fr/openmc/core/features/events/halloween/models/HalloweenData.java rename to src/main/java/fr/openmc/core/features/events/contents/halloween/models/HalloweenData.java index 038ad60a5..ffc4cac6e 100644 --- a/src/main/java/fr/openmc/core/features/events/halloween/models/HalloweenData.java +++ b/src/main/java/fr/openmc/core/features/events/contents/halloween/models/HalloweenData.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.events.halloween.models; +package fr.openmc.core.features.events.contents.halloween.models; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; diff --git a/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/WeeklyEventsManager.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/WeeklyEventsManager.java new file mode 100644 index 000000000..7441bd546 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/WeeklyEventsManager.java @@ -0,0 +1,260 @@ +package fr.openmc.core.features.events.contents.weeklyevents; + +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.TableUtils; +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.Contest; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEvent; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventPhase; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventsData; +import fr.openmc.core.utils.DateUtils; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitTask; + +import java.sql.SQLException; +import java.util.List; + +public class WeeklyEventsManager { + + private static final List EVENTS = List.of( + new Contest() + ); + + private static Dao dao; + private static WeeklyEventsData data; + private static BukkitTask currentTask = null; + + /** + * Initialise la gestion des WeeklyEvents. + * Au restart : si on est déjà le bon jour pour la phase courante et que l'event + * était actif, on relance l'action immédiatement. + */ + public static void init() { + data = load(); + + WeeklyEventPhase currentPhase = getCurrentPhase(); + if (data.isActive() && currentPhase != null && DateUtils.getCurrentDayOfWeek().equals(currentPhase.getStartDay())) { + Runnable action = currentPhase.runAction(); + if (action != null) action.run(); + } + + scheduleNextPhase(); + } + + /** + * Initialise la BDD : crée la table si nécessaire, charge les données, gère le cas restart + */ + public static void initDB(ConnectionSource connectionSource) throws SQLException { + dao = DaoManager.createDao(connectionSource, WeeklyEventsData.class); + TableUtils.createTableIfNotExists(connectionSource, WeeklyEventsData.class); + } + + /** + * Charge les données depuis la BDD, ou crée une ligne par défaut si inexistante. + */ + public static WeeklyEventsData load() { + try { + WeeklyEventsData data = dao.queryForId(1); + if (data == null) { + data = new WeeklyEventsData(0, 0); + dao.create(data); + } + return data; + } catch (SQLException e) { + throw new RuntimeException("Erreur lors du chargement de WeeklyEventData", e); + } + } + + /** + * Sauvegarde les données en BDD. + */ + public static void save(WeeklyEventsData data) { + try { + dao.createOrUpdate(data); + } catch (SQLException e) { + throw new RuntimeException("Erreur lors de la sauvegarde de WeeklyEventData", e); + } + } + + /** + * Retourne l'event en cours. + */ + public static WeeklyEvent getCurrentEvent() { + return EVENTS.get(data.getCurrentEventIndex()); + } + + /** + * Retourne l'instance de WeeklyEvent correspondant à la classe donnée, ou null si introuvable. + */ + public static WeeklyEvent getEvent(Class eventClass) { + return EVENTS.stream() + .filter(event -> event.getClass().equals(eventClass)) + .findFirst() + .orElse(null); + } + + /** + * Retourne la phase en cours selon l'index en BDD, ou null si invalide. + */ + public static WeeklyEventPhase getCurrentPhase() { + List phases = getCurrentEvent().getPhases(); + int index = data.getCurrentPhaseIndex(); + if (index < 0 || index >= phases.size()) return null; + return phases.get(index); + } + + /** + * Retourne true si un event est actuellement actif (flag BDD). + * Source de vérité : le flag active, pas le temps. + */ + public static boolean isEventActive() { + return data.isActive(); + } + + /** + * Planifie la prochaine phase. + * Cancel la task précédente pour éviter les doublons. + * Guard intégré : si findNextPhase() a changé entre le schedule et l'exécution + * (suite à un force), on se recalibre sans exécuter la mauvaise action. + */ + public static void scheduleNextPhase() { + if (currentTask != null) { + currentTask.cancel(); + currentTask = null; + } + + WeeklyEventPhase nextPhase = findNextPhase(); + if (nextPhase == null) return; + + long delayTicks = DateUtils.getSecondsUntilDayOfWeekTime( + nextPhase.getStartDay(), + nextPhase.getStartHour(), + nextPhase.getStartMinutes(), + 0 + ) * 20L; + + if (delayTicks <= 0) { + runPhase(nextPhase); + return; + } + + currentTask = Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { + if (findNextPhase() != nextPhase) { + scheduleNextPhase(); + return; + } + runPhase(nextPhase); + }, delayTicks); + } + + /** + * Exécute l'action de la phase, marque l'event comme actif, + * avance l'état, puis schedule la suivante. + */ + private static void runPhase(WeeklyEventPhase phase) { + data.setActive(true); + save(data); + + Runnable action = phase.runAction(); + if (action != null) action.run(); + + advancePhase(); + scheduleNextPhase(); + } + + /** + * Avance à la phase suivante. + * Si c'était la dernière phase, passe à l'event suivant (et marque inactif). + */ + private static void advancePhase() { + List phases = getCurrentEvent().getPhases(); + int nextPhaseIndex = data.getCurrentPhaseIndex() + 1; + + if (nextPhaseIndex >= phases.size()) { + advanceToNextEvent(); + } else { + data.setCurrentPhaseIndex(nextPhaseIndex); + save(data); + } + } + + /** + * Force un event à une phase spécifique. + * Met à jour la BDD, exécute l'action, gère le cas dernière phase, + * puis reschedule proprement. + */ + public static void forceEventAtPhase(WeeklyEvent event, WeeklyEventPhase phase) { + int eventIndex = EVENTS.indexOf(event); + int phaseIndex = event.getPhases().indexOf(phase); + + if (eventIndex == -1 || phaseIndex == -1) { + OMCPlugin.getInstance().getSLF4JLogger().error("[WeeklyEvents] Event ou phase non trouvé"); + return; + } + + data.setCurrentEventIndex(eventIndex); + data.setCurrentPhaseIndex(phaseIndex); + data.setActive(true); + save(data); + + Runnable action = phase.runAction(); + if (action != null) action.run(); + + boolean isLastPhase = phaseIndex == event.getPhases().size() - 1; + if (isLastPhase) { + advanceToNextEvent(); + } + + scheduleNextPhase(); + + OMCPlugin.getInstance().getSLF4JLogger().info("[WeeklyEvents] Event forcé : {} à la phase {}", + PlainTextComponentSerializer.plainText().serialize(event.getName()), + PlainTextComponentSerializer.plainText().serialize(phase.getName())); + } + + /** + * Passe à l'event suivant, réinitialise la phase à 0 et marque l'event comme inactif. + */ + private static void advanceToNextEvent() { + data.setActive(false); + int nextIndex = (data.getCurrentEventIndex() + 1) % EVENTS.size(); + data.setCurrentEventIndex(nextIndex); + data.setCurrentPhaseIndex(0); + save(data); + + OMCPlugin.getInstance().getSLF4JLogger().info("[WeeklyEvents] Passage à l'event suivant : {}", + PlainTextComponentSerializer.plainText().serialize(getCurrentEvent().getName())); + } + + /** + * Cherche la prochaine phase à venir en parcourant tous les events cycliquement. + * Commence à la phase courante de l'event courant, puis les events suivants depuis 0. + */ + private static WeeklyEventPhase findNextPhase() { + int totalEvents = EVENTS.size(); + + for (int i = 0; i < totalEvents; i++) { + int eventIdx = (data.getCurrentEventIndex() + i) % totalEvents; + WeeklyEvent event = EVENTS.get(eventIdx); + List phases = event.getPhases(); + + int phaseStart = (i == 0) ? data.getCurrentPhaseIndex() : 0; + + for (int j = phaseStart; j < phases.size(); j++) { + WeeklyEventPhase phase = phases.get(j); + long delay = DateUtils.getSecondsUntilDayOfWeekTime( + phase.getStartDay(), + phase.getStartHour(), + phase.getStartMinutes(), + 0 + ); + if (delay >= 0) return phase; + } + } + + return null; + } +} \ No newline at end of file diff --git a/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/Contest.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/Contest.java new file mode 100644 index 000000000..f7db60aa1 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/Contest.java @@ -0,0 +1,38 @@ +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest; + +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEvent; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventPhase; +import fr.openmc.core.registry.items.CustomItemRegistry; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.inventory.ItemStack; + +import java.util.Arrays; +import java.util.List; + +public class Contest extends WeeklyEvent { + @Override + public Component getName() { + return Component.text("Contest", NamedTextColor.GOLD, TextDecoration.BOLD); + } + + @Override + public List getDescription() { + return List.of( + Component.text("2 camps s'affrontent pendant le weekend", NamedTextColor.GRAY), + Component.text("Votez pour votre camp, et participez à l'affrontement !", NamedTextColor.GRAY), + Component.text("Le camp gagnant remportera des récompenses exclusives !", NamedTextColor.GRAY) + ); + } + + @Override + public ItemStack getIcon() { + return CustomItemRegistry.getByName("omc_contest:contest_shell").getBest(); + } + + @Override + public List getPhases() { + return Arrays.stream(ContestPhase.values()).map(ContestPhase::getPhase).toList(); + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/ContestPhase.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/ContestPhase.java new file mode 100644 index 000000000..8dbdc77f1 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/ContestPhase.java @@ -0,0 +1,125 @@ +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest; + +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventPhase; +import lombok.Getter; +import net.kyori.adventure.text.Component; + +import java.time.DayOfWeek; +import java.util.Arrays; +import java.util.List; + +@Getter +public enum ContestPhase { + VOTE_CAMP(new WeeklyEventPhase() { + @Override + public Component getName() { + return Component.text("Les votes"); + } + + @Override + public List getDescription() { + return Arrays.asList( + Component.text("§7Tout les vendredi, le contest commence"), + Component.text("§7Et les votes s'ouvrent, et il faut choisir"), + Component.text("§7Entre 2 camps, une ambience se crée dans le spawn...") + ); + } + + @Override + public DayOfWeek getStartDay() { + return DayOfWeek.FRIDAY; + } + + @Override + public int getStartHour() { + return 0; + } + + @Override + public int getStartMinutes() { + return 0; + } + + @Override + public Runnable runAction() { + return ContestManager::initPhase1; + } + }), + TRADE_PHASE(new WeeklyEventPhase() { + @Override + public Component getName() { + return Component.text("L'affrontement"); + } + + @Override + public List getDescription() { + return Arrays.asList( + Component.text("§7La nuit tombe sur le spawn pendant 2 jours"), + Component.text("§7Que la fête commence !"), + Component.text("§7Des trades sont disponible"), + Component.text("§7Donnant des coquillages de contest !")); + } + + @Override + public DayOfWeek getStartDay() { + return DayOfWeek.SATURDAY; + } + + @Override + public int getStartHour() { + return 0; + } + + @Override + public int getStartMinutes() { + return 0; + } + + @Override + public Runnable runAction() { + return ContestManager::initPhase2; + } + }), + END_PHASE(new WeeklyEventPhase() { + @Override + public Component getName() { + return Component.text("Les résultats"); + } + + @Override + public List getDescription() { + return Arrays.asList( + Component.text("§7Le levé de soleil sur le spawn !"), + Component.text("§7Les résultats tombent, et un camp"), + Component.text("§7sera gagnant. Et des récompenses seront attribuées"), + Component.text(("§7à chacun."))); + } + + @Override + public DayOfWeek getStartDay() { + return DayOfWeek.MONDAY; + } + + @Override + public int getStartHour() { + return 0; + } + + @Override + public int getStartMinutes() { + return 0; + } + + @Override + public Runnable runAction() { + return ContestManager::initPhase3; + } + }) + ; + + private final WeeklyEventPhase phase; + ContestPhase(WeeklyEventPhase phase) { + this.phase = phase; + } +} diff --git a/src/main/java/fr/openmc/core/features/contest/commands/ContestCommand.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/ContestCommand.java similarity index 54% rename from src/main/java/fr/openmc/core/features/contest/commands/ContestCommand.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/ContestCommand.java index 608af262f..9f82c3ea3 100644 --- a/src/main/java/fr/openmc/core/features/contest/commands/ContestCommand.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/ContestCommand.java @@ -1,13 +1,18 @@ -package fr.openmc.core.features.contest.commands; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.commands; import fr.openmc.core.commands.autocomplete.OnlinePlayerAutoComplete; -import fr.openmc.core.features.contest.commands.autocomplete.ColorContestAutoComplete; -import fr.openmc.core.features.contest.commands.autocomplete.TradeContestAutoComplete; -import fr.openmc.core.features.contest.managers.ContestManager; -import fr.openmc.core.features.contest.managers.ContestPlayerManager; -import fr.openmc.core.features.contest.managers.TradeYMLManager; -import fr.openmc.core.features.contest.menu.ContributionMenu; -import fr.openmc.core.features.contest.menu.VoteMenu; +import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.Contest; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestPhase; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.commands.autocomplete.ColorContestAutoComplete; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.commands.autocomplete.ContestPhaseAutoComplete; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.commands.autocomplete.TradeContestAutoComplete; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestPlayerManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.TradeYMLManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu.ContributionMenu; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu.VoteMenu; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventPhase; import fr.openmc.core.utils.DateUtils; import fr.openmc.core.utils.messages.MessageType; import fr.openmc.core.utils.messages.MessagesManager; @@ -18,9 +23,10 @@ import revxrsal.commands.annotation.*; import revxrsal.commands.bukkit.annotation.CommandPermission; -import java.time.DayOfWeek; -import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; @Command("contest") @Description("Ouvre l'interface des festivals, et quand un festival commence, vous pouvez choisir votre camp") @@ -28,39 +34,33 @@ public class ContestCommand { @Cooldown(4) @CommandPlaceholder() public static void mainCommand(Player player) { - int phase = ContestManager.data.getPhase(); - if ((phase >= 2 && ContestManager.dataPlayer.get(player.getUniqueId()) == null) || (phase == 2)) { - VoteMenu menu = new VoteMenu(player); - menu.open(); - } else if (phase == 3 && ContestManager.dataPlayer.get(player.getUniqueId()) != null) { - ContributionMenu menu = new ContributionMenu(player); - menu.open(); + Contest contest = (Contest) WeeklyEventsManager.getEvent(Contest.class); - } else { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E", Locale.FRENCH); - DayOfWeek dayStartContestOfWeek = DayOfWeek.from(formatter.parse(ContestManager.data.getStartdate())); + if (!contest.isActive()) { + int days = (ContestPhase.VOTE_CAMP.getPhase().getStartDay().getValue() + - DateUtils.getCurrentDayOfWeek().getValue() + 7) % 7; + MessagesManager.sendMessage(player, Component.text("§cIl n'y a aucun Contest ! Revenez dans " + days + " jour(s)."), Prefix.CONTEST, MessageType.ERROR, true); + return; + } - int days = (dayStartContestOfWeek.getValue() - DateUtils.getCurrentDayOfWeek().getValue() + 7) % 7; + WeeklyEventPhase activePhase = contest.getActivePhase(); - MessagesManager.sendMessage(player, Component.text("§cIl n'y a aucun Contest ! Revenez dans " + days + " jour(s)."), Prefix.CONTEST, MessageType.ERROR, true); + if (activePhase == ContestPhase.VOTE_CAMP.getPhase()) { + new VoteMenu(player).open(); + } else if (activePhase == ContestPhase.TRADE_PHASE.getPhase()) { + if (ContestManager.dataPlayer.get(player.getUniqueId()) != null) { + new ContributionMenu(player).open(); + } else { + new VoteMenu(player).open(); + } } } @Subcommand("setphase") @Description("Permet de lancer une procédure de phase") @CommandPermission("omc.admin.commands.contest.setphase") - public void setPhase(@Named("phase") @Suggest({"1", "2", "3"}) Integer phase) { - switch(phase) { - case 2: - ContestManager.initPhase2(); - break; - case 3: - ContestManager.initPhase3(); - break; - default: - ContestManager.initPhase1(); - break; - } + public void setPhase(@Named("phase") @SuggestWith(ContestPhaseAutoComplete.class) String phase) { + WeeklyEventsManager.forceEventAtPhase(WeeklyEventsManager.getEvent(Contest.class), ContestPhase.valueOf(phase).getPhase()); } @Subcommand("setcontest") @@ -73,19 +73,25 @@ public void setContest( @Named("nom du camp 2") String camp2, @Named("couleur du camp 2") @SuggestWith(ColorContestAutoComplete.class) String color2 ) { - int phase = ContestManager.data.getPhase(); - if (phase == 1) { - // It is unique, but it is for performance reasons - if (new HashSet<>(ContestManager.getColorContestList()).containsAll(Arrays.asList(color1, color2))) { - ContestManager.clearDB(); - ContestManager.insertCustomContest(camp1, color1, camp2, color2); - - MessagesManager.sendMessage(player, Component.text("§aLe Contest : " + camp1 + " VS " + camp2 + " a bien été sauvegardé\nMerci d'attendre que les données en cache s'actualise."), Prefix.STAFF, MessageType.SUCCESS, true); - } else { - MessagesManager.sendMessage(player, Component.text("§c/contest setcontest et color doit comporter une couleur valide"), Prefix.STAFF, MessageType.ERROR, true); - } + Contest contest = (Contest) WeeklyEventsManager.getEvent(Contest.class); + + if (!contest.isActive()) { + MessagesManager.sendMessage(player, Component.text("§cVous ne pouvez pas définir un contest lorsqu'il n'est pas actif"), Prefix.STAFF, MessageType.ERROR, true); + return; + } + + if (contest.getActivePhase() != ContestPhase.VOTE_CAMP.getPhase()) { + MessagesManager.sendMessage(player, Component.text("§cVous ne pouvez pas définir un contest lorsqu'il a commencé"), Prefix.STAFF, MessageType.ERROR, true); + return; + } + + // It is unique, but it is for performance reasons + if (new HashSet<>(ContestManager.getColorContestList()).containsAll(Arrays.asList(color1, color2))) { + ContestManager.clearDB(); + ContestManager.insertCustomContest(camp1, color1, camp2, color2); + MessagesManager.sendMessage(player, Component.text("§aLe Contest : " + camp1 + " VS " + camp2 + " a bien été sauvegardé\nMerci d'attendre que les données en cache s'actualise."), Prefix.STAFF, MessageType.SUCCESS, true); } else { - MessagesManager.sendMessage(player, Component.text("§cVous pouvez pas définir un contest lorsqu'il a commencé"), Prefix.STAFF, MessageType.ERROR, true); + MessagesManager.sendMessage(player, Component.text("§c/contest setcontest et color doit comporter une couleur valide"), Prefix.STAFF, MessageType.ERROR, true); } } @@ -127,7 +133,9 @@ public void addPoints( @Named("membre") @SuggestWith(OnlinePlayerAutoComplete.class) Player target, @Named("points") Integer points ) { - if (ContestManager.data.getPhase()!=3) { + Contest contest = (Contest) WeeklyEventsManager.getEvent(Contest.class); + + if (contest.getActivePhase() != ContestPhase.TRADE_PHASE.getPhase()) { MessagesManager.sendMessage(player, Component.text("§cVous ne pouvez pas donner des points lorsque le contest n'a pas commencé"), Prefix.STAFF, MessageType.ERROR, true); return; } @@ -137,7 +145,7 @@ public void addPoints( return; } - if (points<=0) { + if (points <= 0) { MessagesManager.sendMessage(player, Component.text("§cVous ne pouvez pas donner des points négatifs ou égal à 0"), Prefix.STAFF, MessageType.ERROR, true); return; } diff --git a/src/main/java/fr/openmc/core/features/contest/commands/autocomplete/ColorContestAutoComplete.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/ColorContestAutoComplete.java similarity index 71% rename from src/main/java/fr/openmc/core/features/contest/commands/autocomplete/ColorContestAutoComplete.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/ColorContestAutoComplete.java index 8375b2f0c..8f1a59d2a 100644 --- a/src/main/java/fr/openmc/core/features/contest/commands/autocomplete/ColorContestAutoComplete.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/ColorContestAutoComplete.java @@ -1,6 +1,6 @@ -package fr.openmc.core.features.contest.commands.autocomplete; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.commands.autocomplete; -import fr.openmc.core.features.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; import org.jetbrains.annotations.NotNull; import revxrsal.commands.autocomplete.SuggestionProvider; import revxrsal.commands.bukkit.actor.BukkitCommandActor; diff --git a/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/ContestPhaseAutoComplete.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/ContestPhaseAutoComplete.java new file mode 100644 index 000000000..2ed0801db --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/ContestPhaseAutoComplete.java @@ -0,0 +1,20 @@ +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.commands.autocomplete; + +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestPhase; +import org.jetbrains.annotations.NotNull; +import revxrsal.commands.autocomplete.SuggestionProvider; +import revxrsal.commands.bukkit.actor.BukkitCommandActor; +import revxrsal.commands.node.ExecutionContext; + +import java.util.Arrays; +import java.util.List; + +public class ContestPhaseAutoComplete implements SuggestionProvider { + + @Override + public @NotNull List getSuggestions(@NotNull ExecutionContext context) { + return Arrays.stream(ContestPhase.values()) + .map(Enum::name) + .toList(); + } +} diff --git a/src/main/java/fr/openmc/core/features/contest/commands/autocomplete/TradeContestAutoComplete.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/TradeContestAutoComplete.java similarity index 71% rename from src/main/java/fr/openmc/core/features/contest/commands/autocomplete/TradeContestAutoComplete.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/TradeContestAutoComplete.java index d416fd1d8..6bd985dd2 100644 --- a/src/main/java/fr/openmc/core/features/contest/commands/autocomplete/TradeContestAutoComplete.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/commands/autocomplete/TradeContestAutoComplete.java @@ -1,6 +1,6 @@ -package fr.openmc.core.features.contest.commands.autocomplete; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.commands.autocomplete; -import fr.openmc.core.features.contest.managers.TradeYMLManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.TradeYMLManager; import org.jetbrains.annotations.NotNull; import revxrsal.commands.autocomplete.SuggestionProvider; import revxrsal.commands.bukkit.actor.BukkitCommandActor; diff --git a/src/main/java/fr/openmc/core/features/contest/ContestEndEvent.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/events/ContestEndEvent.java similarity index 82% rename from src/main/java/fr/openmc/core/features/contest/ContestEndEvent.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/events/ContestEndEvent.java index c15a04e1b..56b0de067 100644 --- a/src/main/java/fr/openmc/core/features/contest/ContestEndEvent.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/events/ContestEndEvent.java @@ -1,6 +1,6 @@ -package fr.openmc.core.features.contest; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.events; -import fr.openmc.core.features.contest.models.Contest; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models.ContestData; import lombok.Getter; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -19,7 +19,7 @@ public class ContestEndEvent extends Event { /** * Les données associées au contest. */ - private final Contest contestData; + private final ContestData contestData; /** * Liste statique des handlers pour l'événement. @@ -43,7 +43,7 @@ public class ContestEndEvent extends Event { * @param winners La liste des gagnants * @param losers La liste des perdants */ - public ContestEndEvent(Contest contestData, List winners, List losers) { + public ContestEndEvent(ContestData contestData, List winners, List losers) { this.contestData = contestData; this.winners = winners; this.losers = losers; diff --git a/src/main/java/fr/openmc/core/features/contest/listeners/ContestIntractEvents.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/listeners/ContestIntractEvents.java similarity index 88% rename from src/main/java/fr/openmc/core/features/contest/listeners/ContestIntractEvents.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/listeners/ContestIntractEvents.java index 05e9e6c49..d02d878ed 100644 --- a/src/main/java/fr/openmc/core/features/contest/listeners/ContestIntractEvents.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/listeners/ContestIntractEvents.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.contest.listeners; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.listeners; import dev.lone.itemsadder.api.Events.FurnitureInteractEvent; import org.bukkit.Bukkit; diff --git a/src/main/java/fr/openmc/core/features/contest/managers/ContestManager.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/managers/ContestManager.java similarity index 87% rename from src/main/java/fr/openmc/core/features/contest/managers/ContestManager.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/managers/ContestManager.java index 3b5ae4cd8..8b33069e2 100644 --- a/src/main/java/fr/openmc/core/features/contest/managers/ContestManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/managers/ContestManager.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.contest.managers; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; @@ -8,21 +8,20 @@ import fr.openmc.api.menulib.Menu; import fr.openmc.core.CommandsManager; import fr.openmc.core.OMCPlugin; -import fr.openmc.core.features.contest.ContestEndEvent; -import fr.openmc.core.features.contest.commands.ContestCommand; -import fr.openmc.core.features.contest.listeners.ContestIntractEvents; -import fr.openmc.core.features.contest.menu.ContributionMenu; -import fr.openmc.core.features.contest.menu.MoreInfoMenu; -import fr.openmc.core.features.contest.menu.TradeMenu; -import fr.openmc.core.features.contest.menu.VoteMenu; -import fr.openmc.core.features.contest.models.Contest; -import fr.openmc.core.features.contest.models.ContestPlayer; import fr.openmc.core.features.economy.EconomyManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.commands.ContestCommand; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.events.ContestEndEvent; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.listeners.ContestIntractEvents; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu.ContributionMenu; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu.MoreInfoMenu; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu.TradeMenu; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu.VoteMenu; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models.ContestData; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models.ContestPlayer; import fr.openmc.core.features.leaderboards.LeaderboardManager; import fr.openmc.core.features.mailboxes.MailboxManager; import fr.openmc.core.registry.items.CustomItemRegistry; import fr.openmc.core.utils.ColorUtils; -import fr.openmc.core.utils.DateUtils; import fr.openmc.core.utils.ParticleUtils; import fr.openmc.core.utils.cache.CacheOfflinePlayer; import fr.openmc.core.utils.database.DatabaseManager; @@ -42,7 +41,6 @@ import java.sql.SQLException; import java.text.DecimalFormat; -import java.time.DayOfWeek; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -51,11 +49,7 @@ public class ContestManager { - private static final DayOfWeek START_CONTEST_DAY = DayOfWeek.FRIDAY; - private static final DayOfWeek START_TRADE_CONTEST_DAY = DayOfWeek.SATURDAY; - private static final DayOfWeek END_CONTEST_DAY = DayOfWeek.MONDAY; - - public static Contest data; + public static ContestData data; public static Map dataPlayer = new HashMap<>(); private static final List colorContest = Arrays.asList( @@ -94,19 +88,14 @@ public static void init() { ); // ** MANAGER EXTERNE ** - new TradeYMLManager(); + TradeYMLManager.init(); // ** LOAD DATAS ** initContestData(); loadContestPlayerData(); - - // ** SCHEDULE TASK ** - scheduleStartContest(); - scheduleStartTradeContest(); - scheduleEndContest(); } - private static Dao contestDao; + private static Dao contestDao; private static Dao playerDao; /** @@ -114,8 +103,8 @@ public static void init() { * (création des tables si elles n’existent pas encore) */ public static void initDB(ConnectionSource connectionSource) throws SQLException { - TableUtils.createTableIfNotExists(connectionSource, Contest.class); - contestDao = DaoManager.createDao(connectionSource, Contest.class); + TableUtils.createTableIfNotExists(connectionSource, ContestData.class); + contestDao = DaoManager.createDao(connectionSource, ContestData.class); TableUtils.createTableIfNotExists(connectionSource, ContestPlayer.class); playerDao = DaoManager.createDao(connectionSource, ContestPlayer.class); @@ -129,7 +118,7 @@ public static void initContestData() { try { data = contestDao.queryForFirst(); if (data == null) { - data = new Contest("Mayonnaise", "Ketchup", "YELLOW", "RED", 1, "ven.", 0, 0); + data = new ContestData("Mayonnaise", "Ketchup", "YELLOW", "RED", 0, 0); contestDao.create(data); } } catch (SQLException e) { @@ -180,7 +169,7 @@ public static void saveContestPlayerData() { */ public static void clearDB() { try { - TableUtils.clearTable(DatabaseManager.getConnectionSource(), Contest.class); + TableUtils.clearTable(DatabaseManager.getConnectionSource(), ContestData.class); TableUtils.clearTable(DatabaseManager.getConnectionSource(), ContestPlayer.class); } catch (SQLException e) { throw new RuntimeException(e); @@ -194,7 +183,6 @@ public static void clearDB() { * - Diffuse un message et joue un son aux joueurs connectés */ public static void initPhase1() { - data.setPhase(2); ParticleUtils.color1 = null; ParticleUtils.color2 = null; @@ -230,8 +218,6 @@ public static void initPhase2() { TradeYMLManager.updateColumnBooleanFromRandomTrades(true, (String) trade.get("ress")); } - data.setPhase(3); - Bukkit.broadcast(Component.text(""" §8§m §r §7 @@ -256,8 +242,6 @@ public static void initPhase2() { * - Réinitialise les données en DB pour le prochain contest */ public static void initPhase3() { - data.setPhase(4); - ParticleUtils.color1 = null; ParticleUtils.color2 = null; @@ -571,60 +555,6 @@ public static List getColorContestList() { * Insère un contest personnalisé dans la DB avec 2 camps et leurs couleurs. */ public static void insertCustomContest(String camp1, String color1, String camp2, String color2) { - data = new Contest(camp1, camp2, color1, color2, 1, "ven.", 0, 0); - } - - /** - * Programme le lancement de la phase 1 (votes) chaque vendredi à minuit. - */ - private static void scheduleStartContest() { - long delayInTicks = DateUtils.getSecondsUntilDayOfWeekMidnight(START_CONTEST_DAY) * 20; - - if (data.getPhase() == 1 && DateUtils.getCurrentDayOfWeek().equals(START_CONTEST_DAY)) { - ContestManager.initPhase1(); - } - - Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { - if (data.getPhase() != 1) return; - - ContestManager.initPhase1(); - scheduleStartContest(); - }, delayInTicks); - } - - /** - * Programme le lancement de la phase 2 (contributions) chaque samedi à minuit. - */ - private static void scheduleStartTradeContest() { - long delayInTicks = DateUtils.getSecondsUntilDayOfWeekMidnight(START_TRADE_CONTEST_DAY) * 20; - - if (data.getPhase() == 2 && DateUtils.getCurrentDayOfWeek().equals(START_TRADE_CONTEST_DAY)) { - ContestManager.initPhase2(); - } - - Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { - if (data.getPhase() != 2) return; - - ContestManager.initPhase2(); - scheduleStartTradeContest(); - }, delayInTicks); - } - - /** - * Programme la fin du contest (phase 3) chaque lundi à minuit. - */ - private static void scheduleEndContest() { - long delayInTicks = DateUtils.getSecondsUntilDayOfWeekMidnight(END_CONTEST_DAY) * 20; - - if (data.getPhase() == 3 && DateUtils.getCurrentDayOfWeek().equals(END_CONTEST_DAY)) { - ContestManager.initPhase3(); - } - - Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { - if (data.getPhase() != 3) return; - - ContestManager.initPhase3(); - scheduleEndContest(); - }, delayInTicks); + data = new ContestData(camp1, camp2, color1, color2, 0, 0); } } diff --git a/src/main/java/fr/openmc/core/features/contest/managers/ContestPlayerManager.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/managers/ContestPlayerManager.java similarity index 97% rename from src/main/java/fr/openmc/core/features/contest/managers/ContestPlayerManager.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/managers/ContestPlayerManager.java index 3690b36dd..743943cae 100644 --- a/src/main/java/fr/openmc/core/features/contest/managers/ContestPlayerManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/managers/ContestPlayerManager.java @@ -1,6 +1,6 @@ -package fr.openmc.core.features.contest.managers; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers; -import fr.openmc.core.features.contest.models.ContestPlayer; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models.ContestPlayer; import lombok.Setter; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; diff --git a/src/main/java/fr/openmc/core/features/contest/managers/TradeYMLManager.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/managers/TradeYMLManager.java similarity index 96% rename from src/main/java/fr/openmc/core/features/contest/managers/TradeYMLManager.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/managers/TradeYMLManager.java index 725830124..374f57e73 100644 --- a/src/main/java/fr/openmc/core/features/contest/managers/TradeYMLManager.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/managers/TradeYMLManager.java @@ -1,7 +1,7 @@ -package fr.openmc.core.features.contest.managers; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers; import fr.openmc.core.OMCPlugin; -import fr.openmc.core.features.contest.models.Contest; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models.ContestData; import fr.openmc.core.utils.YmlUtils; import lombok.Getter; import org.bukkit.configuration.file.FileConfiguration; @@ -33,7 +33,7 @@ public class TradeYMLManager { * Constructeur de TradeYMLManager. * Initialise le fichier contest.yml et charge sa configuration. */ - public TradeYMLManager() { + public static void init() { contestFile = new File(OMCPlugin.getInstance().getDataFolder() + "/data", "contest.yml"); loadContestConfig(); } @@ -197,13 +197,11 @@ public static void selectRandomlyContest() { Random random = new Random(); Map selectedContest = leastSelectedContests.get(random.nextInt(leastSelectedContests.size())); - ContestManager.data = new Contest( + ContestManager.data = new ContestData( (String) selectedContest.get("camp1"), (String) selectedContest.get("camp2"), (String) selectedContest.get("color1"), (String) selectedContest.get("color2"), - 1, - "ven.", 0, 0 ); diff --git a/src/main/java/fr/openmc/core/features/contest/menu/ContributionMenu.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/ContributionMenu.java similarity index 96% rename from src/main/java/fr/openmc/core/features/contest/menu/ContributionMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/ContributionMenu.java index 2048a6d74..b3b4300d9 100644 --- a/src/main/java/fr/openmc/core/features/contest/menu/ContributionMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/ContributionMenu.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.contest.menu; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu; import dev.lone.itemsadder.api.CustomStack; import dev.lone.itemsadder.api.FontImages.FontImageWrapper; @@ -6,8 +6,8 @@ import fr.openmc.api.menulib.Menu; import fr.openmc.api.menulib.utils.InventorySize; import fr.openmc.api.menulib.utils.ItemBuilder; -import fr.openmc.core.features.contest.managers.ContestManager; -import fr.openmc.core.features.contest.managers.ContestPlayerManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestPlayerManager; import fr.openmc.core.registry.items.CustomItemRegistry; import fr.openmc.core.utils.ColorUtils; import fr.openmc.core.utils.ItemUtils; diff --git a/src/main/java/fr/openmc/core/features/contest/menu/MoreInfoMenu.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/MoreInfoMenu.java similarity index 86% rename from src/main/java/fr/openmc/core/features/contest/menu/MoreInfoMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/MoreInfoMenu.java index e979d9d20..da09f0c34 100644 --- a/src/main/java/fr/openmc/core/features/contest/menu/MoreInfoMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/MoreInfoMenu.java @@ -1,10 +1,12 @@ -package fr.openmc.core.features.contest.menu; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu; import dev.lone.itemsadder.api.FontImages.FontImageWrapper; import fr.openmc.api.menulib.Menu; import fr.openmc.api.menulib.utils.InventorySize; import fr.openmc.api.menulib.utils.ItemBuilder; -import fr.openmc.core.features.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestPhase; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventPhase; import net.kyori.adventure.text.Component; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -68,10 +70,10 @@ public void onInventoryClick(InventoryClickEvent click) { ); - int phase = ContestManager.data.getPhase(); + WeeklyEventPhase phase = WeeklyEventsManager.getCurrentPhase(); - boolean ench0 = phase == 2; - boolean ench1 = phase == 3; + boolean ench0 = phase == ContestPhase.VOTE_CAMP.getPhase(); + boolean ench1 = phase == ContestPhase.TRADE_PHASE.getPhase(); inventory.put(11, new ItemBuilder(this, Material.BLUE_STAINED_GLASS_PANE, itemMeta -> { itemMeta.displayName(Component.text("§r§1Les votes - Vendredi")); diff --git a/src/main/java/fr/openmc/core/features/contest/menu/TradeMenu.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/TradeMenu.java similarity index 96% rename from src/main/java/fr/openmc/core/features/contest/menu/TradeMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/TradeMenu.java index 812c11753..0f567f2fe 100644 --- a/src/main/java/fr/openmc/core/features/contest/menu/TradeMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/TradeMenu.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.contest.menu; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu; import dev.lone.itemsadder.api.CustomStack; import dev.lone.itemsadder.api.FontImages.FontImageWrapper; @@ -6,9 +6,9 @@ import fr.openmc.api.menulib.Menu; import fr.openmc.api.menulib.utils.InventorySize; import fr.openmc.api.menulib.utils.ItemBuilder; -import fr.openmc.core.features.contest.managers.ContestManager; -import fr.openmc.core.features.contest.managers.ContestPlayerManager; -import fr.openmc.core.features.contest.managers.TradeYMLManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestPlayerManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.TradeYMLManager; import fr.openmc.core.features.mailboxes.MailboxManager; import fr.openmc.core.registry.items.CustomItemRegistry; import fr.openmc.core.utils.ItemUtils; diff --git a/src/main/java/fr/openmc/core/features/contest/menu/VoteMenu.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/VoteMenu.java similarity index 97% rename from src/main/java/fr/openmc/core/features/contest/menu/VoteMenu.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/VoteMenu.java index c1c580989..6fd2860ad 100644 --- a/src/main/java/fr/openmc/core/features/contest/menu/VoteMenu.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/menu/VoteMenu.java @@ -1,12 +1,12 @@ -package fr.openmc.core.features.contest.menu; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.menu; import dev.lone.itemsadder.api.FontImages.FontImageWrapper; import fr.openmc.api.menulib.Menu; import fr.openmc.api.menulib.template.ConfirmMenu; import fr.openmc.api.menulib.utils.InventorySize; import fr.openmc.api.menulib.utils.ItemBuilder; -import fr.openmc.core.features.contest.managers.ContestManager; -import fr.openmc.core.features.contest.models.ContestPlayer; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models.ContestPlayer; import fr.openmc.core.utils.ColorUtils; import fr.openmc.core.utils.messages.MessageType; import fr.openmc.core.utils.messages.MessagesManager; diff --git a/src/main/java/fr/openmc/core/features/contest/models/Contest.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/models/ContestData.java similarity index 83% rename from src/main/java/fr/openmc/core/features/contest/models/Contest.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/models/ContestData.java index 43fd7b0c7..54419d3c6 100644 --- a/src/main/java/fr/openmc/core/features/contest/models/Contest.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/models/ContestData.java @@ -1,18 +1,17 @@ -package fr.openmc.core.features.contest.models; - -import lombok.Getter; -import lombok.Setter; - -import java.util.Objects; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; +import lombok.Getter; +import lombok.Setter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import java.util.Objects; + @Getter @DatabaseTable(tableName = "contests") -public class Contest { +public class ContestData { @DatabaseField(id = true) private int id; // required for Dao.update function @@ -26,29 +25,21 @@ public class Contest { private String color2; @Setter @DatabaseField(canBeNull = false) - private int phase; - @DatabaseField(canBeNull = false) - private String startdate; - @Setter - @DatabaseField(canBeNull = false) private int points1; @Setter @DatabaseField(canBeNull = false) private int points2; - Contest() { + ContestData() { // required for ORMLite } - public Contest(String camp1, String camp2, String color1, String color2, int phase, String startdate, int points1, - int points2) { + public ContestData(String camp1, String camp2, String color1, String color2, int points1, int points2) { this.id = 1; // we will only be storing one row, so we need a constant id this.camp1 = camp1; this.camp2 = camp2; this.color1 = color1; this.color2 = color2; - this.phase = phase; - this.startdate = startdate; this.points1 = points1; this.points2 = points2; } diff --git a/src/main/java/fr/openmc/core/features/contest/models/ContestPlayer.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/models/ContestPlayer.java similarity index 92% rename from src/main/java/fr/openmc/core/features/contest/models/ContestPlayer.java rename to src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/models/ContestPlayer.java index 87649a3ce..6d079ffef 100644 --- a/src/main/java/fr/openmc/core/features/contest/models/ContestPlayer.java +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/contents/contest/models/ContestPlayer.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.contest.models; +package fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; diff --git a/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEvent.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEvent.java new file mode 100644 index 000000000..7cacae58a --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEvent.java @@ -0,0 +1,35 @@ +package fr.openmc.core.features.events.contents.weeklyevents.models; + +import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; +import fr.openmc.core.features.events.models.Event; + +import java.util.List; + +public abstract class WeeklyEvent extends Event { + public abstract List getPhases(); + + /** + * Retourne true si on est temporellement dans une phase active de cet event. + */ + public boolean isActive() { + return WeeklyEventsManager.getCurrentEvent() == this + && WeeklyEventsManager.isEventActive(); + } + + /** + * Retourne la phase active de cet event, ou null si l'event n'est pas actif. + */ + public WeeklyEventPhase getActivePhase() { + if (!isActive()) return null; + return WeeklyEventsManager.getCurrentPhase(); + } + + /** + * Retourne le nombre de semaines d'offset entre la semaine actuelle et la semaine de référence pour cet event. + * Utile pour prédire les événements lointin + * @return Offset + */ + public int getWeekOffset() { + return 0; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEventPhase.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEventPhase.java new file mode 100644 index 000000000..31db7af69 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEventPhase.java @@ -0,0 +1,15 @@ +package fr.openmc.core.features.events.contents.weeklyevents.models; + +import net.kyori.adventure.text.Component; + +import java.time.DayOfWeek; +import java.util.List; + +public abstract class WeeklyEventPhase { + public abstract Component getName(); + public abstract List getDescription(); + public abstract DayOfWeek getStartDay(); + public abstract int getStartHour(); + public abstract int getStartMinutes(); + public abstract Runnable runAction(); +} diff --git a/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEventsData.java b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEventsData.java new file mode 100644 index 000000000..c68f3772a --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/contents/weeklyevents/models/WeeklyEventsData.java @@ -0,0 +1,33 @@ +package fr.openmc.core.features.events.contents.weeklyevents.models; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; +import lombok.Getter; +import lombok.Setter; + +@Getter +@DatabaseTable(tableName = "weekly_event_data") +public class WeeklyEventsData { + + @DatabaseField(id = true, columnName = "id") + private int id = 1; + + @Setter + @DatabaseField(columnName = "current_event_index") + private int currentEventIndex; + + @Setter + @DatabaseField(columnName = "current_phase_index") + private int currentPhaseIndex; + + @Setter + @DatabaseField(columnName = "is_active") + private boolean active; + + public WeeklyEventsData() {} + + public WeeklyEventsData(int currentEventIndex, int currentPhaseIndex) { + this.currentEventIndex = currentEventIndex; + this.currentPhaseIndex = currentPhaseIndex; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/managers/CalendarManager.java b/src/main/java/fr/openmc/core/features/events/managers/CalendarManager.java new file mode 100644 index 000000000..ccc0230df --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/managers/CalendarManager.java @@ -0,0 +1,92 @@ +package fr.openmc.core.features.events.managers; + +import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEvent; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventPhase; +import fr.openmc.core.features.events.models.Event; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.time.DayOfWeek; +import java.util.ArrayList; +import java.util.List; + +public class CalendarManager { + + public static List getUpcomingEvents(int slots) { + List events = new ArrayList<>(List.of( + WeeklyEventsManager.getCurrentEvent() + )); + + //todo: implement DailyEvent in upcoming events + + if (events.getLast() instanceof WeeklyEvent we) { + for (int i = events.size(); i <= slots; i++) { + int weekOffset = i; + + events.add(new WeeklyEvent() { + + @Override + public int getWeekOffset() { + return weekOffset; + } + + @Override + public List getPhases() { + return List.of(new WeeklyEventPhase() { + @Override + public Component getName() { + return Component.text("Inconnu"); + } + + @Override + public List getDescription() { + return List.of(); + } + + @Override + public DayOfWeek getStartDay() { + return we.getPhases().getFirst().getStartDay(); + } + + @Override + public int getStartHour() { + return 0; + } + + @Override + public int getStartMinutes() { + return 0; + } + + @Override + public Runnable runAction() { + return null; + } + }); + } + + @Override + public Component getName() { + return Component.text("Evenement du Weekend", NamedTextColor.YELLOW, TextDecoration.BOLD); + } + + @Override + public List getDescription() { + return List.of(); + } + + @Override + public ItemStack getIcon() { + return ItemStack.of(Material.GOLD_BLOCK); + } + }); + } + } + + return events; + } +} diff --git a/src/main/java/fr/openmc/core/features/events/menus/CalendarMenu.java b/src/main/java/fr/openmc/core/features/events/menus/CalendarMenu.java new file mode 100644 index 000000000..4058c9705 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/menus/CalendarMenu.java @@ -0,0 +1,130 @@ +package fr.openmc.core.features.events.menus; + +import fr.openmc.api.menulib.PaginatedMenu; +import fr.openmc.api.menulib.utils.InventorySize; +import fr.openmc.api.menulib.utils.ItemBuilder; +import fr.openmc.api.menulib.utils.StaticSlots; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEvent; +import fr.openmc.core.features.events.contents.weeklyevents.models.WeeklyEventPhase; +import fr.openmc.core.features.events.managers.CalendarManager; +import fr.openmc.core.features.events.models.Event; +import fr.openmc.core.registry.items.CustomItemRegistry; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +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.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.TextStyle; +import java.time.temporal.TemporalAdjusters; +import java.util.*; + +public class CalendarMenu extends PaginatedMenu { + public CalendarMenu(Player owner) { + super(owner); + } + + @Override + public @Nullable Material getBorderMaterial() { + return Material.AIR; + } + + @Override + public @NotNull List getStaticSlots() { + return StaticSlots.getStandardSlots(getInventorySize()); + } + + @Override + public List getItems() { + List items = new ArrayList<>(); + for (Event event : CalendarManager.getUpcomingEvents(14)) { + items.add(new ItemBuilder(this, event.getIcon(), meta -> { + meta.customName(event.getName().decoration(TextDecoration.ITALIC, false)); + meta.lore(getEventLore(event)); + })); + } + return items; + } + + @Override + public List getTakableSlot() { + return List.of(); + } + + @Override + public @NotNull InventorySize getInventorySize() { + return InventorySize.LARGE; + } + + @Override + public int getSizeOfItems() { + return getItems().size(); + } + + @Override + public Map getButtons() { + Map map = new HashMap<>(); + map.put(33, new ItemBuilder(this, Objects.requireNonNull(CustomItemRegistry.getByName("_iainternal:icon_cancel")).getBest(), itemMeta -> itemMeta.displayName(Component.text("§7Fermer"))).setCloseButton()); + return map; + } + + private List getEventLore(Event event) { + List eventLore = new ArrayList<>(event.getDescription()); + + if (event instanceof WeeklyEvent we) { + eventLore.add(Component.empty()); + eventLore.add(Component.text("Phases :", NamedTextColor.GOLD, TextDecoration.BOLD).decoration(TextDecoration.ITALIC, false)); + for (WeeklyEventPhase phase : we.getPhases()) { + LocalDateTime now = LocalDateTime.now(); + + LocalDate nextDate = now.toLocalDate() + .with(TemporalAdjusters.nextOrSame(phase.getStartDay())) + .plusWeeks(we.getWeekOffset()); + + LocalDateTime dateEvent = nextDate.atTime( + phase.getStartHour(), + phase.getStartMinutes() + ); + + String formattedDate = dateEvent.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.FRANCE) + + " " + dateEvent.getDayOfMonth() + " " + + dateEvent.getMonth().getDisplayName(TextStyle.FULL, Locale.FRANCE); + // ex. Vendredi 13 Mars + + eventLore.add(Component.text("- ") + .append(phase.getName()) + .append(Component.text(" le " + formattedDate + " à " + + phase.getStartHour() + "h" + String.format("%02d", phase.getStartMinutes()))) // ex. 0h00 + .color(NamedTextColor.GRAY) + .decoration(TextDecoration.ITALIC, false) + ); + } + } + return eventLore; + } + + @Override + public @NotNull String getName() { + return "Calendrier Evenementiel"; + } + + @Override + public String getTexture() { + return null; + } + + @Override + public void onInventoryClick(InventoryClickEvent e) {} + + @Override + public void onClose(InventoryCloseEvent event) { + //empty + } +} diff --git a/src/main/java/fr/openmc/core/features/events/models/Event.java b/src/main/java/fr/openmc/core/features/events/models/Event.java new file mode 100644 index 000000000..feec507be --- /dev/null +++ b/src/main/java/fr/openmc/core/features/events/models/Event.java @@ -0,0 +1,13 @@ +package fr.openmc.core.features.events.models; + +import net.kyori.adventure.text.Component; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public abstract class Event { + public abstract Component getName(); + public abstract List getDescription(); + public abstract ItemStack getIcon(); + +} diff --git a/src/main/java/fr/openmc/core/features/leaderboards/LeaderboardManager.java b/src/main/java/fr/openmc/core/features/leaderboards/LeaderboardManager.java index fa688a272..6ac6e32fc 100644 --- a/src/main/java/fr/openmc/core/features/leaderboards/LeaderboardManager.java +++ b/src/main/java/fr/openmc/core/features/leaderboards/LeaderboardManager.java @@ -7,8 +7,8 @@ import fr.openmc.core.features.economy.BankManager; import fr.openmc.core.features.economy.EconomyManager; import fr.openmc.core.features.economy.models.EconomyPlayer; -import fr.openmc.core.features.events.halloween.managers.HalloweenManager; -import fr.openmc.core.features.events.halloween.models.HalloweenData; +import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.models.HalloweenData; import fr.openmc.core.features.leaderboards.commands.LeaderboardCommands; import fr.openmc.core.utils.DateUtils; import fr.openmc.core.utils.entities.TextDisplay; diff --git a/src/main/java/fr/openmc/core/features/mainmenu/menus/Page1.java b/src/main/java/fr/openmc/core/features/mainmenu/menus/Page1.java index d81ce2858..1b7e92aa8 100644 --- a/src/main/java/fr/openmc/core/features/mainmenu/menus/Page1.java +++ b/src/main/java/fr/openmc/core/features/mainmenu/menus/Page1.java @@ -13,10 +13,13 @@ import fr.openmc.core.features.city.City; import fr.openmc.core.features.city.CityManager; import fr.openmc.core.features.city.commands.CityCommands; -import fr.openmc.core.features.contest.commands.ContestCommand; -import fr.openmc.core.features.contest.managers.ContestManager; -import fr.openmc.core.features.contest.models.Contest; import fr.openmc.core.features.dream.DreamUtils; +import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.Contest; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestPhase; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.commands.ContestCommand; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.models.ContestData; import fr.openmc.core.features.homes.command.TpHomeCommand; import fr.openmc.core.features.mailboxes.MailboxCommand; import fr.openmc.core.features.mainmenu.listeners.PacketListener; @@ -107,9 +110,9 @@ public Page1(Player player) { MILESTONES_SLOTS.forEach(slot -> content.put(slot, milestonesItem)); ItemStack contestItem = new ItemStack(Material.PAPER); - Contest data = ContestManager.data; - int phase = data.getPhase(); - if (phase != 1) { + ContestData data = ContestManager.data; + + if (WeeklyEventsManager.getCurrentEvent() instanceof Contest && WeeklyEventsManager.getCurrentPhase() != ContestPhase.END_PHASE.getPhase()) { contestItem.editMeta(meta -> { meta.setItemModel(NamespacedKey.minecraft("air")); meta.itemName(data.getCampVSComponent()); diff --git a/src/main/java/fr/openmc/core/features/quests/quests/WinContestQuest.java b/src/main/java/fr/openmc/core/features/quests/quests/WinContestQuest.java index 484b5af98..01939956e 100644 --- a/src/main/java/fr/openmc/core/features/quests/quests/WinContestQuest.java +++ b/src/main/java/fr/openmc/core/features/quests/quests/WinContestQuest.java @@ -1,6 +1,6 @@ package fr.openmc.core.features.quests.quests; -import fr.openmc.core.features.contest.ContestEndEvent; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.events.ContestEndEvent; import fr.openmc.core.features.quests.objects.Quest; import fr.openmc.core.features.quests.objects.QuestTier; import fr.openmc.core.features.quests.rewards.QuestItemReward; diff --git a/src/main/java/fr/openmc/core/utils/DateUtils.java b/src/main/java/fr/openmc/core/utils/DateUtils.java index 608245495..3fd482348 100644 --- a/src/main/java/fr/openmc/core/utils/DateUtils.java +++ b/src/main/java/fr/openmc/core/utils/DateUtils.java @@ -173,10 +173,10 @@ public static String getTimeUntilNextDay(DayOfWeek day) { return String.format("%dd %dh %dm", days, hours, minutes); } - public static long getSecondsUntilDayOfWeekMidnight(DayOfWeek dayOfWeek) { + public static long getSecondsUntilDayOfWeekTime(DayOfWeek dayOfWeek, int hour, int minute, int second) { LocalDateTime now = LocalDateTime.now(); LocalDateTime nextDayOfWeekMidnight = now.with(TemporalAdjusters.nextOrSame(dayOfWeek)) - .withHour(0).withMinute(0).withSecond(0).withNano(0); + .withHour(hour).withMinute(minute).withSecond(second).withNano(0); if (!now.isBefore(nextDayOfWeekMidnight)) { nextDayOfWeekMidnight = nextDayOfWeekMidnight.plusWeeks(1); diff --git a/src/main/java/fr/openmc/core/utils/ParticleUtils.java b/src/main/java/fr/openmc/core/utils/ParticleUtils.java index c9bd808e8..b498b6575 100644 --- a/src/main/java/fr/openmc/core/utils/ParticleUtils.java +++ b/src/main/java/fr/openmc/core/utils/ParticleUtils.java @@ -6,7 +6,10 @@ import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import fr.openmc.core.OMCPlugin; -import fr.openmc.core.features.contest.managers.ContestManager; +import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.Contest; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.ContestPhase; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; import net.kyori.adventure.text.format.NamedTextColor; import net.minecraft.core.particles.DustParticleOptions; import net.minecraft.network.protocol.game.ClientboundLevelParticlesPacket; @@ -54,7 +57,8 @@ public static void spawnParticlesInRegion(String regionId, World world, Particle new BukkitRunnable() { @Override public void run() { - if (ContestManager.data.getPhase() == 3) return; + if (!(WeeklyEventsManager.getCurrentEvent() instanceof Contest)) return; + if (WeeklyEventsManager.getCurrentPhase() == ContestPhase.END_PHASE.getPhase()) return; for (int i = 0; i < amountPer2Tick; i++) { double x = RandomUtils.randomBetween(minLocation.getX(), maxLocation.getX()); @@ -123,7 +127,8 @@ public static void spawnContestParticlesInRegion(String regionId, World world, i new BukkitRunnable() { @Override public void run() { - if (ContestManager.data.getPhase() != 3) return; + if (!(WeeklyEventsManager.getCurrentEvent() instanceof Contest)) return; + if (WeeklyEventsManager.getCurrentPhase() == ContestPhase.END_PHASE.getPhase()) return; if (color1 == null || color2 == null) { String camp1Color = ContestManager.data.getColor1(); diff --git a/src/main/java/fr/openmc/core/utils/database/DatabaseManager.java b/src/main/java/fr/openmc/core/utils/database/DatabaseManager.java index 4fdacadc6..6b3309d6b 100644 --- a/src/main/java/fr/openmc/core/utils/database/DatabaseManager.java +++ b/src/main/java/fr/openmc/core/utils/database/DatabaseManager.java @@ -12,12 +12,13 @@ import fr.openmc.core.features.city.sub.rank.CityRankManager; import fr.openmc.core.features.city.sub.statistics.CityStatisticsManager; import fr.openmc.core.features.city.sub.war.WarManager; -import fr.openmc.core.features.contest.managers.ContestManager; import fr.openmc.core.features.dream.DreamManager; import fr.openmc.core.features.economy.BankManager; import fr.openmc.core.features.economy.EconomyManager; import fr.openmc.core.features.economy.TransactionsManager; -import fr.openmc.core.features.events.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.halloween.managers.HalloweenManager; +import fr.openmc.core.features.events.contents.weeklyevents.WeeklyEventsManager; +import fr.openmc.core.features.events.contents.weeklyevents.contents.contest.managers.ContestManager; import fr.openmc.core.features.friend.FriendSQLManager; import fr.openmc.core.features.homes.HomesManager; import fr.openmc.core.features.mailboxes.MailboxManager; @@ -63,6 +64,7 @@ public static void init() { AnalyticsManager.initDB(connectionSource); MailboxManager.initDB(connectionSource); ContestManager.initDB(connectionSource); + WeeklyEventsManager.initDB(connectionSource); EconomyManager.initDB(connectionSource); HomesManager.initDB(connectionSource); FriendSQLManager.initDB(connectionSource); From 4e549dab93bcca94301b34e10874f8f029c56f33 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sun, 5 Apr 2026 13:39:28 +0200 Subject: [PATCH 52/52] =?UTF-8?q?Correction=20du=20fait=20de=20pouvoir=20i?= =?UTF-8?q?nt=C3=A9ragir=20avec=20la=20statue=20de=20cuivre=20d'une=20autr?= =?UTF-8?q?e=20villle=20(#1238)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix copper golem statue pose with hand main * make /leaderboard not in dev --- .../features/city/listeners/protections/InteractProtection.java | 1 - src/main/java/fr/openmc/core/features/mainmenu/menus/Page2.java | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/city/listeners/protections/InteractProtection.java b/src/main/java/fr/openmc/core/features/city/listeners/protections/InteractProtection.java index 62fa495da..01d3f6fa4 100644 --- a/src/main/java/fr/openmc/core/features/city/listeners/protections/InteractProtection.java +++ b/src/main/java/fr/openmc/core/features/city/listeners/protections/InteractProtection.java @@ -29,7 +29,6 @@ public void onInteract(PlayerInteractEvent event) { Player player = event.getPlayer(); if (event.getAction() == Action.PHYSICAL) return; - if (event.getHand() != EquipmentSlot.HAND) return; if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return; Block clickedBlock = event.getClickedBlock(); diff --git a/src/main/java/fr/openmc/core/features/mainmenu/menus/Page2.java b/src/main/java/fr/openmc/core/features/mainmenu/menus/Page2.java index a07177541..6651adecd 100644 --- a/src/main/java/fr/openmc/core/features/mainmenu/menus/Page2.java +++ b/src/main/java/fr/openmc/core/features/mainmenu/menus/Page2.java @@ -102,7 +102,7 @@ public Page2() { leaderboardItem.editMeta(meta -> { meta.setItemModel(NamespacedKey.minecraft("air")); meta.itemName(Component.text("Leaderboard", NamedTextColor.YELLOW)); - meta.lore(List.of(Component.text("/leaderboard", NamedTextColor.DARK_GRAY), Component.text("En cours de développement", NamedTextColor.RED))); + meta.lore(List.of(Component.text("/leaderboard", NamedTextColor.DARK_GRAY))); }); LEADERBOARD_SLOTS.forEach(slot -> content.put(slot, leaderboardItem));