diff --git a/.github/workflows/milestone-close.yml b/.github/workflows/milestone-close.yml index 59b52640f..486899530 100644 --- a/.github/workflows/milestone-close.yml +++ b/.github/workflows/milestone-close.yml @@ -58,10 +58,10 @@ jobs: GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} - name: Deploy to server - uses: rexlmanu/pterodactyl-upload-action@v2.4 + 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: builds/OpenMC.jar - target: "./plugins/OpenMC.jar" + target: "./plugins/update/" diff --git a/src/main/java/fr/openmc/api/hooks/FancyNpcsHook.java b/src/main/java/fr/openmc/api/hooks/FancyNpcsHook.java index 4c2cbc7ae..c2c5e3810 100644 --- a/src/main/java/fr/openmc/api/hooks/FancyNpcsHook.java +++ b/src/main/java/fr/openmc/api/hooks/FancyNpcsHook.java @@ -7,6 +7,8 @@ public class FancyNpcsHook { @Getter private static boolean hasFancyNpc = false; + public static long FANCY_INIT_DELAY = 20L * 30; // 30 seconds + public static void init() { hasFancyNpc = Bukkit.getPluginManager().isPluginEnabled("FancyNpcs"); } diff --git a/src/main/java/fr/openmc/core/features/city/view/CityViewManager.java b/src/main/java/fr/openmc/core/features/city/view/CityViewManager.java index 05a1e7cbd..944219cf7 100644 --- a/src/main/java/fr/openmc/core/features/city/view/CityViewManager.java +++ b/src/main/java/fr/openmc/core/features/city/view/CityViewManager.java @@ -186,8 +186,8 @@ private static void showChunkBorders(@NotNull Player player, @NotNull ChunkPos c particleLocations.forEach(location -> ParticleUtils.sendParticlePacket( player, - location, particle, + location, 1, 0D, 0D, 0D, 0D, 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 a50f64540..67d5feff5 100644 --- a/src/main/java/fr/openmc/core/features/dream/DreamManager.java +++ b/src/main/java/fr/openmc/core/features/dream/DreamManager.java @@ -18,17 +18,15 @@ import fr.openmc.core.features.dream.generation.listeners.CloudStructureDispenserListener; import fr.openmc.core.features.dream.generation.listeners.ReplaceBlockListener; import fr.openmc.core.features.dream.generation.structures.DreamStructuresManager; -import fr.openmc.core.features.dream.listeners.biomes.PlayerEnteredBiome; import fr.openmc.core.features.dream.listeners.dream.*; -import fr.openmc.core.features.dream.listeners.orb.PlayerObtainOrb; -import fr.openmc.core.features.dream.listeners.others.CraftingConvertorListener; -import fr.openmc.core.features.dream.listeners.others.PlayerEatSomnifere; -import fr.openmc.core.features.dream.listeners.others.SingularityCraftListener; +import fr.openmc.core.features.dream.listeners.registry.CraftingConvertorListener; import fr.openmc.core.features.dream.listeners.registry.DreamItemEquipListener; import fr.openmc.core.features.dream.mecanism.cloudfishing.CloudFishingManager; import fr.openmc.core.features.dream.mecanism.cold.ColdManager; import fr.openmc.core.features.dream.mecanism.metaldetector.MetalDetectorManager; import fr.openmc.core.features.dream.mecanism.rng.DreamLootListener; +import fr.openmc.core.features.dream.mecanism.sfx.PlayerCloneNpc; +import fr.openmc.core.features.dream.mecanism.singularity.SingularityCraftListener; import fr.openmc.core.features.dream.mecanism.singularity.SingularityManager; import fr.openmc.core.features.dream.mecanism.tradernpc.GlaciteNpcManager; import fr.openmc.core.features.dream.models.db.DBDreamPlayer; @@ -43,7 +41,6 @@ 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; @@ -90,6 +87,7 @@ public static void init() { // ** MANAGERS ** DreamDimensionManager.init(); GlaciteNpcManager.init(); + PlayerCloneNpc.init(); DreamStructuresManager.init(); DreamItemRegistry.init(); DreamLootTableRegistry.init(); diff --git a/src/main/java/fr/openmc/core/features/dream/commands/AdminDreamCommands.java b/src/main/java/fr/openmc/core/features/dream/commands/AdminDreamCommands.java index 9a8d99d97..5b0ac85e7 100644 --- a/src/main/java/fr/openmc/core/features/dream/commands/AdminDreamCommands.java +++ b/src/main/java/fr/openmc/core/features/dream/commands/AdminDreamCommands.java @@ -2,7 +2,7 @@ import fr.openmc.core.commands.autocomplete.OnlinePlayerAutoComplete; import fr.openmc.core.features.dream.DreamManager; -import fr.openmc.core.features.dream.listeners.orb.PlayerObtainOrb; +import fr.openmc.core.features.dream.listeners.dream.PlayerObtainOrb; import fr.openmc.core.features.dream.models.db.DBDreamPlayer; import fr.openmc.core.features.dream.models.db.DreamPlayer; import org.bukkit.entity.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 84ba003f7..a2ddcf071 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 @@ -1,14 +1,20 @@ package fr.openmc.core.features.dream.listeners.dream; +import fr.openmc.core.OMCPlugin; 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.displays.DreamBossBar; +import fr.openmc.core.features.dream.mecanism.sfx.PlayerCloneNpc; import fr.openmc.core.features.dream.models.db.DreamPlayer; +import fr.openmc.core.utils.ParticleUtils; +import org.bukkit.Bukkit; +import org.bukkit.Particle; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; import org.bukkit.entity.Player; +import org.bukkit.entity.Pose; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerTeleportEvent; @@ -44,6 +50,13 @@ public void onDreamEntrered(PlayerTeleportEvent event) { AttributeInstance inst = player.getAttribute(Attribute.MAX_HEALTH); if (inst == null) return; player.setHealth(inst.getBaseValue()); + + // * SFX + sendSFX(player); + if (PlayerCloneNpc.getCloneNpc(player) == null) + PlayerCloneNpc.createCloneNpc(player, player.getLocation(), Pose.SITTING); + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> + sendSFX(player), 20); } @EventHandler @@ -62,5 +75,16 @@ public void onDreamLeave(PlayerTeleportEvent event) { BossbarManager.removeBossBar(BossbarsType.DREAM, player); DreamManager.removeDreamPlayer(player, event.getFrom()); + + // * SFX + sendSFX(player); + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> + sendSFX(player), 20); + } + + private void sendSFX(Player player) { + // * SFX + ParticleUtils.sendParticlePacket(Particle.FLASH, player.getLocation().add(0, 1, 0), 15); + ParticleUtils.spawnDispersingParticles(player.getLocation(), Particle.REVERSE_PORTAL, 20, 15, 1, null); } } diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerDreamTimeEndListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerDreamTimeEndListener.java index 6e0397584..d0566b044 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerDreamTimeEndListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerDreamTimeEndListener.java @@ -2,6 +2,7 @@ import fr.openmc.core.features.dream.DreamManager; import fr.openmc.core.features.dream.events.DreamEndEvent; +import fr.openmc.core.features.dream.mecanism.sfx.PlayerCloneNpc; import fr.openmc.core.features.dream.models.db.DreamPlayer; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -13,6 +14,7 @@ public class PlayerDreamTimeEndListener implements Listener { public void onTimeEnd(DreamEndEvent event) { Player player = event.getPlayer(); + PlayerCloneNpc.deleteCloneNpc(player); DreamPlayer dreamPlayer = DreamManager.getDreamPlayer(player); if (dreamPlayer == null) return; diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/others/PlayerEatSomnifere.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerEatSomnifere.java similarity index 97% rename from src/main/java/fr/openmc/core/features/dream/listeners/others/PlayerEatSomnifere.java rename to src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerEatSomnifere.java index d900b9c1c..b617396c6 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/others/PlayerEatSomnifere.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerEatSomnifere.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.dream.listeners.others; +package fr.openmc.core.features.dream.listeners.dream; import fr.openmc.core.features.dream.DreamManager; import fr.openmc.core.features.dream.DreamUtils; diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/biomes/PlayerEnteredBiome.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerEnteredBiome.java similarity index 98% rename from src/main/java/fr/openmc/core/features/dream/listeners/biomes/PlayerEnteredBiome.java rename to src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerEnteredBiome.java index 6f35dacdf..3dda3f761 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/biomes/PlayerEnteredBiome.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerEnteredBiome.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.dream.listeners.biomes; +package fr.openmc.core.features.dream.listeners.dream; import fr.openmc.core.OMCPlugin; import fr.openmc.core.features.dream.DreamManager; @@ -103,8 +103,8 @@ private void applyFog(Player player) { private void spawnParticles(Player player) { ParticleUtils.sendParticlePacket( player, - player.getLocation(), Particle.CLOUD, + player.getLocation(), 100, 1.0, 1.0, 1.0, 0.1, null ); } diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerFoodChangeListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerFoodChangeListener.java index 6918e719f..f338aac5b 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerFoodChangeListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerFoodChangeListener.java @@ -2,7 +2,6 @@ import fr.openmc.core.features.dream.DreamManager; import fr.openmc.core.features.dream.DreamUtils; -import fr.openmc.core.features.dream.listeners.orb.PlayerObtainOrb; import fr.openmc.core.features.dream.models.db.DBDreamPlayer; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/orb/PlayerObtainOrb.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerObtainOrb.java similarity index 64% rename from src/main/java/fr/openmc/core/features/dream/listeners/orb/PlayerObtainOrb.java rename to src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerObtainOrb.java index 712f95abb..2cfb50502 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/orb/PlayerObtainOrb.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerObtainOrb.java @@ -1,8 +1,7 @@ -package fr.openmc.core.features.dream.listeners.orb; +package fr.openmc.core.features.dream.listeners.dream; import fr.openmc.core.OMCPlugin; import fr.openmc.core.features.dream.DreamManager; -import fr.openmc.core.features.dream.DreamUtils; import fr.openmc.core.features.dream.events.GlaciteTradeEvent; import fr.openmc.core.features.dream.events.MetalDetectorLootEvent; import fr.openmc.core.features.dream.generation.DreamBiome; @@ -12,19 +11,18 @@ import fr.openmc.core.features.dream.models.db.DreamPlayer; import fr.openmc.core.features.dream.models.registry.items.DreamItem; import fr.openmc.core.features.dream.registries.DreamItemRegistry; +import fr.openmc.core.utils.ParticleUtils; import fr.openmc.core.utils.messages.MessageType; import fr.openmc.core.utils.messages.MessagesManager; import fr.openmc.core.utils.messages.Prefix; import net.kyori.adventure.text.Component; -import org.bukkit.Keyed; -import org.bukkit.NamespacedKey; +import org.bukkit.Particle; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityPickupItemEvent; -import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.event.inventory.CraftItemEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.Recipe; public class PlayerObtainOrb implements Listener { private final int SCULK_PLAINS_ORB = 1; @@ -34,20 +32,21 @@ public class PlayerObtainOrb implements Listener { private final int GLACITE_GROTTO_ORB = 5; @EventHandler - public void onCraft(PrepareItemCraftEvent event) { - Recipe recipe = event.getRecipe(); - if (recipe == null) return; - if (event.getViewers().isEmpty()) return; + public void onCraft(CraftItemEvent event) { + ItemStack item = event.getCurrentItem(); + if (item == null) return; - Player player = (Player) event.getViewers().getFirst(); + DreamItem dreamItem = DreamItemRegistry.getByItemStack(item); + if (dreamItem == null) return; + if (!(event.getWhoClicked() instanceof Player player)) return; - if (!DreamUtils.isInDream(player)) return; - if (!(recipe instanceof Keyed keyed)) return; + if (!dreamItem.getName().equals("omc_dream:domination_orb")) return; - NamespacedKey key = keyed.getKey(); - if (key.toString().contains("omc_dream") && key.toString().contains("domination_orb")) { // contains beacuse key is ex zzzfake_omc_items:aywenite - setProgressionOrb(player, SCULK_PLAINS_ORB, DreamBiome.SOUL_FOREST); - } + setProgressionOrb(player, SCULK_PLAINS_ORB, DreamBiome.SOUL_FOREST); + + // * SFX + player.getWorld().playSound(player.getLocation(), "minecraft:entity.wither.spawn", 1f, 2f); + ParticleUtils.spawnDispersingParticles(player.getLocation(), Particle.TRIAL_SPAWNER_DETECTION, 15, 15, 0.5, null); } @EventHandler @@ -60,6 +59,10 @@ public void onAltarCraft(AltarCraftingEvent event) { Player player = event.getPlayer(); setProgressionOrb(player, SOUL_FOREST_ORB, DreamBiome.CLOUD_LAND); + + // * SFX + player.getWorld().playSound(player.getLocation(), "minecraft:entity.wither.spawn", 1f, 2f); + ParticleUtils.spawnDispersingParticles(player.getLocation(), Particle.SCULK_SOUL, 15, 15, 0.5, null); } @EventHandler @@ -73,6 +76,10 @@ public void onCloudOrbDispense(EntityPickupItemEvent event) { if (!dreamItem.getName().equals("omc_dream:cloud_orb")) return; setProgressionOrb(player, CLOUD_CASTLE_ORB, DreamBiome.MUD_BEACH); + + // * SFX + player.getWorld().playSound(player.getLocation(), "minecraft:entity.wither.spawn", 1f, 2f); + ParticleUtils.spawnDispersingParticles(player.getLocation(), Particle.GUST, 15, 15, 0.5, null); } @EventHandler @@ -86,6 +93,10 @@ public void onMetalDetectorLoot(MetalDetectorLootEvent event) { if (!dreamItem.getName().equals("omc_dream:mud_orb")) continue; setProgressionOrb(player, MUD_BEACH_ORB, DreamBiome.GLACITE_GROTTO); + + // * SFX + player.getWorld().playSound(player.getLocation(), "minecraft:entity.wither.spawn", 1f, 2f); + ParticleUtils.spawnDispersingParticles(player.getLocation(), Particle.ASH, 15, 15, 0.5, null); break; } } @@ -97,6 +108,10 @@ public void onGlaciteTrade(GlaciteTradeEvent event) { if (!event.getTrade().equals(GlaciteTrade.ORB_GLACITE)) return; setProgressionOrb(player, GLACITE_GROTTO_ORB, null); + + // * SFX + player.getWorld().playSound(player.getLocation(), "minecraft:entity.wither.spawn", 1f, 2f); + ParticleUtils.spawnDispersingParticles(player.getLocation(), Particle.SNOWFLAKE, 15, 15, 0.5, null); } public static void setProgressionOrb(Player player, int progressionOrb, DreamBiome unlocked) { @@ -122,6 +137,21 @@ public static void setProgressionOrb(Player player, int progressionOrb, DreamBio DreamManager.saveDreamPlayerData(cache); if (unlocked != null) sendMessageProgression(player, unlocked); + sendBroadcastMessageOrb(player, progressionOrb); + } + + private static void sendBroadcastMessageOrb(Player player, int progressionOrb) { + String strOrb; + switch (progressionOrb) { + case 1 -> strOrb = "l'Orbe de Domination"; + case 2 -> strOrb = "l'Orbe des Ames"; + case 3 -> strOrb = "l'Orbe des Nuages"; + case 4 -> strOrb = "l'Orbe de Boue"; + case 5 -> strOrb = "l'Orbe Glaciale"; + default -> strOrb = "une Orbe Inconnu"; + } + + MessagesManager.broadcastMessage(player.getWorld(), Component.text(player.getName() + " a obtenu " + strOrb + " !"), Prefix.DREAM, MessageType.INFO); } private static void sendMessageProgression(Player player, DreamBiome biome) { diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerQuitListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerQuitListener.java index dd2726ddb..518f94866 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerQuitListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerQuitListener.java @@ -2,6 +2,7 @@ import fr.openmc.core.features.dream.DreamManager; import fr.openmc.core.features.dream.DreamUtils; +import fr.openmc.core.features.dream.mecanism.sfx.PlayerCloneNpc; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -16,6 +17,8 @@ public void onPlayerQuitWhenDream(PlayerQuitEvent event) { if (!DreamUtils.isInDream(player)) return; + if (PlayerCloneNpc.getCloneNpc(player) != null) + PlayerCloneNpc.deleteCloneNpc(player); DreamManager.removeDreamPlayer(player, player.getLocation()); } } 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 ea51e3ce2..c02c31e2e 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 @@ -2,9 +2,11 @@ import fr.openmc.core.OMCPlugin; import fr.openmc.core.features.dream.DreamManager; +import fr.openmc.core.features.dream.mecanism.sfx.PlayerCloneNpc; import fr.openmc.core.features.dream.models.db.DBDreamPlayer; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.entity.Pose; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerBedEnterEvent; @@ -25,7 +27,7 @@ public class PlayerSleepListener implements Listener { private final Set isPlayerSleeping = new HashSet<>(); private final int DREAM_TELEPORT_DELAY = 20 * 3; - + @EventHandler public void onPlayerEnterBed(PlayerBedEnterEvent event) { Player player = event.getPlayer(); @@ -60,6 +62,7 @@ public void onNightSkip(TimeSkipEvent event) { new BukkitRunnable() { @Override public void run() { + PlayerCloneNpc.createCloneNpc(player, player.getLocation(), Pose.SLEEPING); DBDreamPlayer dbDreamPlayer = DreamManager.getCacheDreamPlayer(player); if(dbDreamPlayer ==null||(dbDreamPlayer.getDreamX()==null||dbDreamPlayer.getDreamY()==null||dbDreamPlayer.getDreamZ()==null)) { DreamManager.tpPlayerDream(player); diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/others/SingularityCraftListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/others/SingularityCraftListener.java deleted file mode 100644 index 82d598bee..000000000 --- a/src/main/java/fr/openmc/core/features/dream/listeners/others/SingularityCraftListener.java +++ /dev/null @@ -1,26 +0,0 @@ -package fr.openmc.core.features.dream.listeners.others; - -import fr.openmc.core.features.dream.models.registry.items.DreamItem; -import fr.openmc.core.features.dream.registries.DreamItemRegistry; -import fr.openmc.core.features.mailboxes.MailboxManager; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.CraftItemEvent; -import org.bukkit.inventory.ItemStack; - -public class SingularityCraftListener implements Listener { - @EventHandler - public void onCraft(CraftItemEvent event) { - ItemStack item = event.getCurrentItem(); - if (item == null) return; - - DreamItem dreamItem = DreamItemRegistry.getByItemStack(item); - if (dreamItem == null) return; - if (!(event.getWhoClicked() instanceof Player player)) return; - - if (dreamItem.getName().equals("omc_dream:singularity")) { - MailboxManager.sendItems(player, player, new ItemStack[] { dreamItem.getBest() }); - } - } -} diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/others/CraftingConvertorListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/registry/CraftingConvertorListener.java similarity index 98% rename from src/main/java/fr/openmc/core/features/dream/listeners/others/CraftingConvertorListener.java rename to src/main/java/fr/openmc/core/features/dream/listeners/registry/CraftingConvertorListener.java index 540d0dbff..92b55e996 100644 --- a/src/main/java/fr/openmc/core/features/dream/listeners/others/CraftingConvertorListener.java +++ b/src/main/java/fr/openmc/core/features/dream/listeners/registry/CraftingConvertorListener.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.dream.listeners.others; +package fr.openmc.core.features.dream.listeners.registry; import fr.openmc.core.features.dream.DreamUtils; import fr.openmc.core.features.dream.models.registry.items.DreamItem; diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/cloudfishing/CloudFishingManager.java b/src/main/java/fr/openmc/core/features/dream/mecanism/cloudfishing/CloudFishingManager.java index 09ee8d11d..bd7332b44 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/cloudfishing/CloudFishingManager.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/cloudfishing/CloudFishingManager.java @@ -6,8 +6,6 @@ import fr.openmc.core.registry.loottable.CustomLootTableRegistry; import fr.openmc.core.utils.ParticleUtils; import lombok.Getter; -import net.kyori.adventure.key.Key; -import net.minecraft.network.chat.ClickEvent; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.Sound; @@ -59,9 +57,9 @@ public void run() { double z = start.getZ() + (hookLoc.getZ() - start.getZ()) * t; Location point = new Location(world, x, y, z); - ParticleUtils.sendParticlePacket(player, point.add(0, 1, 0), Particle.WITCH, 3, 0.1, 0.1, 0.1, 0.01, null); + ParticleUtils.sendParticlePacket(player, Particle.WITCH, point.add(0, 1, 0), 3, 0.1, 0.1, 0.1, 0.01, null); - ParticleUtils.spawnParticleCloud(player, point, Particle.CLOUD, 65, 5, 1.5); + ParticleUtils.spawnCloudParticles(player, Particle.CLOUD, point, 65, 5, 1.5); counter[0]++; @@ -78,17 +76,10 @@ private static void onFishBite(Player player, FishHook hook) { player.playSound(player.getLocation(), Sound.ENTITY_FISHING_BOBBER_SPLASH, 0.6F, 1F); - ParticleUtils.sendParticlePacket( - player, - hook.getLocation().add(0, 1, 0), + ParticleUtils.spawnDispersingParticles(player, Particle.DRAGON_BREATH, - 35, - 0.3D, - 0.2D, - 0.3D, - 0.1D, - (Float) 1.0f - ); + hook.getLocation().add(0, 1, 0), + 35, 0.1D, null); hookedPlayers.put(player.getUniqueId(), new FishBiteTask(player, hook, 20L)); } diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/cold/ColdManager.java b/src/main/java/fr/openmc/core/features/dream/mecanism/cold/ColdManager.java index 53fdb709d..02377ae7a 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/cold/ColdManager.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/cold/ColdManager.java @@ -112,7 +112,7 @@ public static void applyColdEffects(Player player, int cold) { } if (level > 0) { - ParticleUtils.sendParticlePacket(player, player.getLocation().add(0, 1, 0), Particle.SPIT, 10, 0.3, 0.5, 0.3, 0.01, null); + ParticleUtils.sendParticlePacket(player, Particle.SPIT, player.getLocation().add(0, 1, 0), 10, 0.3, 0.5, 0.3, 0.01, null); } } diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/CloneParticlesTask.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/CloneParticlesTask.java new file mode 100644 index 000000000..a51531119 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/CloneParticlesTask.java @@ -0,0 +1,17 @@ +package fr.openmc.core.features.dream.mecanism.sfx; + +import fr.openmc.core.utils.ParticleUtils; +import org.bukkit.Location; +import org.bukkit.scheduler.BukkitRunnable; + +public class CloneParticlesTask extends BukkitRunnable { + + private final Location sleepingLocation; + public CloneParticlesTask(Location sleepingLocation) { + this.sleepingLocation = sleepingLocation; + } + @Override + public void run() { + ParticleUtils.spawnConvergingParticles(sleepingLocation, 15); + } +} diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/PlayerCloneNpc.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/PlayerCloneNpc.java new file mode 100644 index 000000000..2754e42e3 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/PlayerCloneNpc.java @@ -0,0 +1,175 @@ +package fr.openmc.core.features.dream.mecanism.sfx; + +import de.oliver.fancynpcs.api.FancyNpcsPlugin; +import de.oliver.fancynpcs.api.Npc; +import de.oliver.fancynpcs.api.NpcData; +import de.oliver.fancynpcs.api.NpcManager; +import de.oliver.fancynpcs.api.utils.NpcEquipmentSlot; +import fr.openmc.api.hooks.FancyNpcsHook; +import fr.openmc.core.OMCPlugin; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.type.Bed; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.entity.Pose; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.scheduler.BukkitTask; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class PlayerCloneNpc { + private static final String prefixNpc = "npcp-"; + private static final NpcManager NPC_MANAGER = FancyNpcsPlugin.get().getNpcManager(); + private static final HashMap particlesTasks = new HashMap<>(); + + /** + * Intitialize the PlayerCloneNpc system. + * This method should be called during the plugin's initialization phase. + * It fetches all existing NPCs after a delay to ensure that the FancyNpcs plugin has fully initialized, + * and removes any NPCs that match the player clone prefix. + */ + public static void init() { + // fetch les npcs apres 30 secondes le temps que fancy npc s'initialise. + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> { + FancyNpcsPlugin.get().getNpcManager().getAllNpcs().forEach(npc -> { + if (npc.getData().getName().startsWith(prefixNpc)) { + deleteCloneNpc(npc); + } + }); + }, FancyNpcsHook.FANCY_INIT_DELAY); + } + + /** + * Get the clone NPC associated with a player, if it exists. + * @param player The player for whom to retrieve the clone NPC. + * @return The clone NPC associated with the player, or null if no such NPC exists. + */ + public static Npc getCloneNpc(Player player) { + return NPC_MANAGER.getNpc(prefixNpc + player.getUniqueId()); + } + + /** + * Creates a clone NPC for the specified player at the given sleeping location. + * @param player The player for whom to create the clone NPC. + * @param sleepingLocation The location where the player is sleeping, which will be used to position the clone NPC. + */ + public static void createCloneNpc(Player player, Location sleepingLocation, Pose pose) { + if (!FancyNpcsHook.isHasFancyNpc()) return; + Npc existingNpc = getCloneNpc(player); + if (existingNpc != null) { + deleteCloneNpc(existingNpc); + } + String npcUUID = prefixNpc + player.getUniqueId(); + + sleepingLocation = getExactSleepingLocation(sleepingLocation); + NpcData data = new NpcData(npcUUID, player.getUniqueId(), sleepingLocation.clone()); + + // * Set Configure type + data.setType(EntityType.PLAYER); + data.setDisplayName(""); + + // * Player clone specific attributes + data.setSkin(player.getName()); + data.addAttribute(FancyNpcsPlugin.get().getAttributeManager().getAttributeByName(EntityType.PLAYER, "pose"), pose.name().toLowerCase()); + + // * Set equipement + Map equipment = new HashMap<>(); + PlayerInventory inv = player.getInventory(); + + equipment.put(NpcEquipmentSlot.HEAD, inv.getHelmet()); + equipment.put(NpcEquipmentSlot.CHEST, inv.getChestplate()); + equipment.put(NpcEquipmentSlot.LEGS, inv.getLeggings()); + equipment.put(NpcEquipmentSlot.FEET, inv.getBoots()); + equipment.put(NpcEquipmentSlot.MAINHAND, inv.getItemInMainHand()); + equipment.put(NpcEquipmentSlot.OFFHAND, inv.getItemInOffHand()); + + data.setEquipment(equipment); + + // * Register and spawn npc + Npc npc = FancyNpcsPlugin.get().getNpcAdapter().apply(data); + NPC_MANAGER.registerNpc(npc); + npc.create(); + npc.spawnForAll(); + + // * SFX + particlesTasks.put(player.getUniqueId(), + new CloneParticlesTask(sleepingLocation.add(0, 1, 0)).runTaskTimer(OMCPlugin.getInstance(), 0L, 40L) + ); + } + + /** + * Deletes the specified clone NPC, removing it from the world and unregistering it from the NPC manager. + * @param player The player whose clone NPC should be deleted. If the player does not have a clone NPC, this method will do nothing. + */ + public static void deleteCloneNpc(Player player) { + if (!FancyNpcsHook.isHasFancyNpc()) return; + Npc npc = getCloneNpc(player); + if (npc == null) return; + + deleteCloneNpc(npc); + } + + /** + * Deletes the specified clone NPC, removing it from the world and unregistering it from the NPC manager. + * @param npc The clone NPC to be deleted. If the NPC does not exist or is not a clone NPC, this method will do nothing. + */ + public static void deleteCloneNpc(Npc npc) { + if (!FancyNpcsHook.isHasFancyNpc()) return; + if (npc == null) return; + if (NPC_MANAGER.getNpc(npc.getData().getName()) == null) return; + + Npc toRemove = NPC_MANAGER.getNpc(npc.getData().getName()); + // * cancel particles task + UUID owner = npc.getData().getCreator(); + if (particlesTasks.containsKey(owner)) { + particlesTasks.remove(owner).cancel(); + } + + // * remove npc + toRemove.removeForAll(); + NPC_MANAGER.removeNpc(toRemove); + } + + /** + * Calculates the exact location where the clone NPC should be spawned based on the player's sleeping location. + * @param sleepingLocation The location where the player is sleeping + * @return The adjusted location where the clone NPC should be spawned, with the correct position and orientation to match the player's sleeping position on the bed. + */ + public static Location getExactSleepingLocation(Location sleepingLocation) { + Block bed = sleepingLocation.getBlock(); + + // * fallback + if (!(bed.getBlockData() instanceof Bed bedData)) { + return sleepingLocation; + } + + // * on part du pied de lit + Block footBlock = bedData.getPart() == Bed.Part.FOOT ? bed : bed.getRelative(bedData.getFacing().getOppositeFace()); + + // * on prends un yaw correspondant a la directon du lit + float yaw = switch (bedData.getFacing()) { + case NORTH -> -90f; + case SOUTH -> 90f; + case EAST -> 0f; + case WEST -> 180f; + default -> 0f; + }; + + // * on calcul nos offsets pour centrer le npc sur le lit + BlockFace facing = bedData.getFacing(); + double offsetX = facing.getModX() * 0.5; + double offsetZ = facing.getModZ() * 0.5; + + // * on return la loc finale + Location result = footBlock.getLocation().add(0.5 - offsetX, 0.6, 0.5 - offsetZ); + result.setYaw(yaw); + result.setPitch(0f); + return result; + } +} diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/singularity/SingularityCraftListener.java b/src/main/java/fr/openmc/core/features/dream/mecanism/singularity/SingularityCraftListener.java new file mode 100644 index 000000000..dc8aa18fa --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/singularity/SingularityCraftListener.java @@ -0,0 +1,42 @@ +package fr.openmc.core.features.dream.mecanism.singularity; + +import fr.openmc.core.features.dream.models.registry.items.DreamItem; +import fr.openmc.core.features.dream.registries.DreamItemRegistry; +import fr.openmc.core.features.mailboxes.MailboxManager; +import fr.openmc.core.utils.ParticleUtils; +import fr.openmc.core.utils.messages.MessageType; +import fr.openmc.core.utils.messages.MessagesManager; +import fr.openmc.core.utils.messages.Prefix; +import net.kyori.adventure.text.Component; +import org.bukkit.Particle; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.CraftItemEvent; +import org.bukkit.inventory.ItemStack; + +public class SingularityCraftListener implements Listener { + @EventHandler + public void onCraft(CraftItemEvent event) { + ItemStack item = event.getCurrentItem(); + if (item == null) return; + + DreamItem dreamItem = DreamItemRegistry.getByItemStack(item); + if (dreamItem == null) return; + if (!(event.getWhoClicked() instanceof Player player)) return; + + if (!dreamItem.getName().equals("omc_dream:singularity")) return; + + MailboxManager.sendItems(player, player, new ItemStack[] { dreamItem.getBest() }); + + // * SFX + World world = player.getWorld(); + world.strikeLightningEffect(player.getLocation()); + ParticleUtils.spawnDispersingParticles(player.getLocation(), Particle.OMINOUS_SPAWNING, 25, 15, 0.1, null); + ParticleUtils.spawnDispersingParticles(player.getLocation(), Particle.FLASH, 5, 15, 0.05, null); + world.playSound(player.getLocation(), "minecraft:entity.wither.death", 1f, 0.1f); + + MessagesManager.broadcastMessage(Component.text(player.getName() + " a crafté une Singularité !"), Prefix.DREAM, MessageType.INFO); + } +} diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/tradernpc/GlaciteNpcManager.java b/src/main/java/fr/openmc/core/features/dream/mecanism/tradernpc/GlaciteNpcManager.java index a7be28927..1fc52043f 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/tradernpc/GlaciteNpcManager.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/tradernpc/GlaciteNpcManager.java @@ -28,7 +28,7 @@ public static void init() { npc.removeForAll(); } }); - }, 20L * 30); + }, FancyNpcsHook.FANCY_INIT_DELAY); } } diff --git a/src/main/java/fr/openmc/core/features/dream/registries/mobs/Breezy.java b/src/main/java/fr/openmc/core/features/dream/registries/mobs/Breezy.java index 78800de75..5c0642c4b 100644 --- a/src/main/java/fr/openmc/core/features/dream/registries/mobs/Breezy.java +++ b/src/main/java/fr/openmc/core/features/dream/registries/mobs/Breezy.java @@ -84,8 +84,8 @@ private static void shootWindCharge(Breeze breeze, Player target) { ParticleUtils.sendParticlePacket( target, - eye, Particle.CLOUD, + eye, 20, 0.2, 0.2, 0.2, 0.01, null ); } 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()); } } } diff --git a/src/main/java/fr/openmc/core/utils/ParticleUtils.java b/src/main/java/fr/openmc/core/utils/ParticleUtils.java index c9bd808e8..737d64201 100644 --- a/src/main/java/fr/openmc/core/utils/ParticleUtils.java +++ b/src/main/java/fr/openmc/core/utils/ParticleUtils.java @@ -16,8 +16,16 @@ import org.bukkit.craftbukkit.CraftParticle; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitRunnable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Supplier; + public class ParticleUtils { private static final double MAX_PARTICLE_DISTANCE_SQR = 100 * 100; @@ -25,6 +33,29 @@ public class ParticleUtils { public static Color color1; public static Color color2; + // based on org.bukkit.craftbukkit.CraftParticle + private static final Map> PARTICLE_FALLBACKS; + + static { + PARTICLE_FALLBACKS = new HashMap<>(); + PARTICLE_FALLBACKS.put("dust", () -> new Particle.DustOptions(Color.RED, 1.0f)); + PARTICLE_FALLBACKS.put("block", Material.STONE::createBlockData); + PARTICLE_FALLBACKS.put("falling_dust", Material.STONE::createBlockData); + PARTICLE_FALLBACKS.put("block_marker", Material.STONE::createBlockData); + PARTICLE_FALLBACKS.put("dust_pillar", Material.STONE::createBlockData); + PARTICLE_FALLBACKS.put("block_crumble", Material.STONE::createBlockData); + PARTICLE_FALLBACKS.put("item", () -> new ItemStack(Material.STONE)); + PARTICLE_FALLBACKS.put("dust_color_transition", () -> new Particle.DustTransition(Color.RED, Color.BLUE, 1.0f)); + PARTICLE_FALLBACKS.put("sculk_charge", () -> 0.0f); + PARTICLE_FALLBACKS.put("dragon_breath", () -> 0.0f); + PARTICLE_FALLBACKS.put("shriek",() -> 0); + PARTICLE_FALLBACKS.put("entity_effect", () -> Color.WHITE); + PARTICLE_FALLBACKS.put("tinted_leaves", () -> Color.WHITE); + PARTICLE_FALLBACKS.put("flash", () -> Color.WHITE); + PARTICLE_FALLBACKS.put("effect", () -> new Particle.Spell(Color.WHITE, 1.0f)); + PARTICLE_FALLBACKS.put("instant_effect", () -> new Particle.Spell(Color.WHITE, 1.0f)); + } + public static void sendRandomCubeParticles(Player player, Particle particle, double radius, int amount) { Location center = player.getLocation(); @@ -75,27 +106,38 @@ public void run() { }.runTaskTimerAsynchronously(OMCPlugin.getInstance(), 0L, 2L); } - public static void sendParticlePacket(Player player, Particle particle, Location loc) { - ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + public static void sendParticlePacket(Particle particle, Location loc, int radius) { + Collection players = loc.getNearbyEntitiesByType(Player.class, radius); - ClientboundLevelParticlesPacket packet = new ClientboundLevelParticlesPacket( - CraftParticle.createParticleParam(particle, null), - false, - false, - loc.getX(), loc.getY(), loc.getZ(), - 0.2f, 0.2f, 0.2f, - 0.01f, - 3 - ); + for (Player player : players) { + sendParticlePacket(player, particle, loc, 3, 0.2f, 0.2f, 0.2f, 0.01f, null); + } + } - nmsPlayer.connection.send(packet); + public static void sendParticlePacket(Player player, Particle particle, Location loc) { + sendParticlePacket(player, particle, loc, 3, 0.2f, 0.2f, 0.2f, 0.01f, null); } - public static void sendParticlePacket(Player player, Location location, Particle particle, int count, double offsetX, double offsetY, double offsetZ, double speed, T data) { + public static void sendParticlePacket(Player player, Particle particle, Location location, int count, double offsetX, double offsetY, double offsetZ, double speed, T data) { ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + // * Fallback pour les data de particule + Object resolvedData; + // Si data est une valeur qui est voulu par le dev + if (data != null) { + resolvedData = data; + } else { + // Si data est null, le dev ne veut rien mettre de spécial, on prend le fallback + Supplier fallback = PARTICLE_FALLBACKS.get(particle.getKey().getKey()); + if (fallback != null) { + resolvedData = fallback.get(); + } else { + resolvedData = null; + } + } + ClientboundLevelParticlesPacket packet = new ClientboundLevelParticlesPacket( - CraftParticle.createParticleParam(particle, data), + CraftParticle.createParticleParam(particle, resolvedData), false, false, location.x(), location.y(), location.z(), @@ -215,7 +257,13 @@ public void run() { }.runTaskTimerAsynchronously(OMCPlugin.getInstance(), 0L, 1L); } - public static void spawnParticleCloud(Player player, Location center, Particle particle, int count, double radius, double height) { + public static void spawnCloudParticles(Location center, Particle particle, int count, double radius, double height) { + for (Player player : center.getNearbyEntitiesByType(Player.class, radius)) { + spawnCloudParticles(player, particle, center, count, radius, height); + } + } + + public static void spawnCloudParticles(Player player, Particle particle, Location center, int count, double radius, double height) { World world = center.getWorld(); if (world == null) return; double minY = center.getY() - Math.abs(height); @@ -232,4 +280,46 @@ public static void spawnParticleCloud(Player player, Location center, Particle p sendParticlePacket(player, particle, loc); } } + + public static void spawnConvergingParticles(Location target, int count) { + Random random = ThreadLocalRandom.current(); + + for (int i = 0; i < count; i++) { + double angle = random.nextDouble() * 2 * Math.PI; + double radius = random.nextDouble() * 5; + + double offsetX = Math.cos(angle) * radius; + double offsetY = 2 + random.nextDouble(); + double offsetZ = Math.sin(angle) * radius; + + Particle.ENCHANT.builder() + .location(target) + .offset(offsetX, offsetY, offsetZ) + .count(0) + .receivers(32, true) + .spawn(); + } + } + + public static void spawnDispersingParticles(Location target, Particle particle, int count, int radius, double speed, T data) { + Collection players = target.getNearbyEntitiesByType(Player.class, radius); + + for (Player player : players) { + spawnDispersingParticles(player, particle, target, count, speed, data); + } + } + + public static void spawnDispersingParticles(Player player, Particle particle, Location target, int count, double speed, T data) { + ParticleUtils.sendParticlePacket( + player, + particle, + target, + count, + 0.3D, + 0.2D, + 0.3D, + speed, + data + ); + } } diff --git a/src/main/java/fr/openmc/core/utils/messages/MessagesManager.java b/src/main/java/fr/openmc/core/utils/messages/MessagesManager.java index b97fbda99..c16d5768f 100644 --- a/src/main/java/fr/openmc/core/utils/messages/MessagesManager.java +++ b/src/main/java/fr/openmc/core/utils/messages/MessagesManager.java @@ -5,6 +5,7 @@ import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -98,6 +99,28 @@ public static void broadcastMessage(Component message, Prefix prefix, MessageTyp Bukkit.broadcast(messageComponent); } + /** + * + * Broadcasts a formatted message to the entire server + * + * @param world The world to broadcast the message in + * @param message The content of the message + * @param prefix The prefix for the message + * @param type The type of message (information, error, success, warning) + */ + public static void broadcastMessage(World world, Component message, Prefix prefix, MessageType type) { + Component messageComponent = + Component.text(type == MessageType.NONE ? "" : "§7(" + type.getPrefix() + "§7) ") + .append(prefix.getPrefix()) + .append(Component.text(" §7» ") + .append(message) + ); + + for (Player player : world.getPlayers()) { + player.sendMessage(messageComponent); + } + } + public static String textToSmall(String text) { if (text == null || text.isEmpty()) return text;