From 6cd41e3d5b2007763d16d807c9d287ac838f310f Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Wed, 3 Jun 2026 21:29:30 +0200 Subject: [PATCH 1/6] impl base of player ghost -> major issue on server restart, -> next make it with NMS --- .../core/features/dream/DreamManager.java | 4 +- .../dream/PlayerChangeWorldListener.java | 2 +- .../dream/PlayerDreamTimeEndListener.java | 2 +- .../listeners/dream/PlayerQuitListener.java | 2 +- .../listeners/dream/PlayerSleepListener.java | 2 +- .../sfx/{ => clone}/CloneParticlesTask.java | 2 +- .../sfx/{ => clone}/PlayerCloneNpc.java | 2 +- .../mecanism/sfx/ghost/DreamGhostManager.java | 108 ++++++++++++++++++ .../listeners/DreamPlayerEnteredListener.java | 29 +++++ .../ghost/listeners/PlayerQuitListener.java | 22 ++++ .../core/utils/bukkit/ParticleUtils.java | 16 ++- 11 files changed, 178 insertions(+), 13 deletions(-) rename src/main/java/fr/openmc/core/features/dream/mecanism/sfx/{ => clone}/CloneParticlesTask.java (88%) rename src/main/java/fr/openmc/core/features/dream/mecanism/sfx/{ => clone}/PlayerCloneNpc.java (99%) create mode 100644 src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java create mode 100644 src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java create mode 100644 src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/PlayerQuitListener.java 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 f664c90e7..2937f27f8 100644 --- a/src/main/java/fr/openmc/core/features/dream/DreamManager.java +++ b/src/main/java/fr/openmc/core/features/dream/DreamManager.java @@ -29,7 +29,8 @@ 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.sfx.clone.PlayerCloneNpc; +import fr.openmc.core.features.dream.mecanism.sfx.ghost.DreamGhostManager; 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; @@ -83,6 +84,7 @@ public void init() { MetalDetectorManager.init(); ColdManager.init(); SingularityManager.init(); + DreamGhostManager.init(); // ** LOAD DATAS ** loadAllDreamPlayerData(); 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 bb85a6d0c..947755669 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 @@ -4,7 +4,7 @@ import fr.openmc.core.features.dream.DreamManager; import fr.openmc.core.features.dream.DreamUtils; import fr.openmc.core.features.dream.events.DreamEnterEvent; -import fr.openmc.core.features.dream.mecanism.sfx.PlayerCloneNpc; +import fr.openmc.core.features.dream.mecanism.sfx.clone.PlayerCloneNpc; import fr.openmc.core.features.dream.models.db.DreamPlayer; import fr.openmc.core.utils.bukkit.ParticleUtils; import org.bukkit.Bukkit; 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 d0566b044..435e77b7c 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,7 +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.mecanism.sfx.clone.PlayerCloneNpc; import fr.openmc.core.features.dream.models.db.DreamPlayer; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; 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 518f94866..e8cea779e 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,7 +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 fr.openmc.core.features.dream.mecanism.sfx.clone.PlayerCloneNpc; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; 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 b039aab15..46cb7045b 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,7 +2,7 @@ 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.mecanism.sfx.clone.PlayerCloneNpc; import fr.openmc.core.features.dream.models.db.DBDreamPlayer; import org.bukkit.entity.Player; import org.bukkit.entity.Pose; 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/clone/CloneParticlesTask.java similarity index 88% rename from src/main/java/fr/openmc/core/features/dream/mecanism/sfx/CloneParticlesTask.java rename to src/main/java/fr/openmc/core/features/dream/mecanism/sfx/clone/CloneParticlesTask.java index b29ff5245..79351f842 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/CloneParticlesTask.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/clone/CloneParticlesTask.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.dream.mecanism.sfx; +package fr.openmc.core.features.dream.mecanism.sfx.clone; import fr.openmc.core.utils.bukkit.ParticleUtils; import org.bukkit.Location; 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/clone/PlayerCloneNpc.java similarity index 99% rename from src/main/java/fr/openmc/core/features/dream/mecanism/sfx/PlayerCloneNpc.java rename to src/main/java/fr/openmc/core/features/dream/mecanism/sfx/clone/PlayerCloneNpc.java index 3e773a229..a710d174e 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/PlayerCloneNpc.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/clone/PlayerCloneNpc.java @@ -1,4 +1,4 @@ -package fr.openmc.core.features.dream.mecanism.sfx; +package fr.openmc.core.features.dream.mecanism.sfx.clone; import de.oliver.fancynpcs.api.FancyNpcsPlugin; import de.oliver.fancynpcs.api.Npc; diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java new file mode 100644 index 000000000..5a2b81ac3 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java @@ -0,0 +1,108 @@ +package fr.openmc.core.features.dream.mecanism.sfx.ghost; + +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.dream.DreamUtils; +import fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners.DreamPlayerEnteredListener; +import fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners.PlayerQuitListener; +import fr.openmc.core.utils.bukkit.ParticleUtils; +import fr.openmc.core.utils.bukkit.SkullUtils; +import org.bukkit.*; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * Gestion des intéractions joueurs dans les reves. + * + * Cache tous les joueurs + met juste leur tete d'affiché avec particule + */ +public class DreamGhostManager { + private static final Map ghostStands = new HashMap<>(); + private static final NamespacedKey GHOST_KEY = new NamespacedKey(OMCPlugin.getInstance(), "ghost_stand"); + + public static void init() { + OMCPlugin.registerEvents( + new DreamPlayerEnteredListener(), + new PlayerQuitListener() + ); + } + + public static void setupGhost(Player player) { + World world = player.getWorld(); + + for (Player other : world.getPlayers()) { + if (!other.equals(player)) { + other.hidePlayer(OMCPlugin.getInstance(), player); + player.hidePlayer(OMCPlugin.getInstance(), other); + } + } + + ArmorStand stand = (ArmorStand) world.spawnEntity(player.getLocation(), EntityType.ARMOR_STAND); + stand.setVisible(false); + stand.setGravity(false); + stand.setCustomNameVisible(false); + stand.setCanPickupItems(false); + stand.setMarker(false); + stand.getPersistentDataContainer().set(GHOST_KEY, PersistentDataType.BOOLEAN, true); + + AttributeInstance instance = stand.getAttribute(Attribute.SCALE); + if (instance == null) return; + + instance.setBaseValue(1.7); + + ItemStack skull = SkullUtils.getPlayerSkull(player.getUniqueId()); + stand.getEquipment().setHelmet(skull); + + ghostStands.put(player.getUniqueId(), stand); + + new BukkitRunnable() { + @Override + public void run() { + if (!player.isOnline() + || !DreamUtils.isInDreamWorld(player) + || !ghostStands.containsKey(player.getUniqueId())) { + removeGhost(player); + this.cancel(); + return; + } + + if (player.getGameMode().equals(GameMode.SPECTATOR)) return; + + Location newStand = player.getLocation().subtract(0, 0.5, 0); + + Collection receivers = newStand.getNearbyEntitiesByType(Player.class, 20).stream() + .filter(p -> !p.equals(player)).toList(); + + ParticleUtils.spawnCloudParticlesToAll( + player.getLocation().add(0, 1.5, 0), Particle.SCULK_SOUL, + 1, 1, 2, receivers); + + Particle.SHRIEK.builder() + .location(newStand) + .data(20) + .receivers(receivers) + .spawn(); + + stand.teleport(newStand); + player.hideEntity(OMCPlugin.getInstance(), stand); + } + }.runTaskTimer(OMCPlugin.getInstance(), 0L, 2L); + } + + public static void removeGhost(Player player) { + ArmorStand stand = ghostStands.get(player.getUniqueId()); + if (stand == null) return; + stand.remove(); + ghostStands.remove(player.getUniqueId()); + } +} diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java new file mode 100644 index 000000000..5c701f45c --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java @@ -0,0 +1,29 @@ +package fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners; + +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.dream.events.DreamEndEvent; +import fr.openmc.core.features.dream.events.DreamEnterEvent; +import fr.openmc.core.features.dream.mecanism.sfx.ghost.DreamGhostManager; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class DreamPlayerEnteredListener implements Listener { + + @EventHandler + public void onDreamEnter(DreamEnterEvent event) { + DreamGhostManager.setupGhost(event.getPlayer()); + } + + @EventHandler + public void onDreamExit(DreamEndEvent event) { + Player player = event.getPlayer(); + DreamGhostManager.removeGhost(player); + + for (Player other : Bukkit.getOnlinePlayers()) { + other.showPlayer(OMCPlugin.getInstance(), player); + player.showPlayer(OMCPlugin.getInstance(), other); + } + } +} diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/PlayerQuitListener.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/PlayerQuitListener.java new file mode 100644 index 000000000..e3161e440 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/PlayerQuitListener.java @@ -0,0 +1,22 @@ +package fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners; + +import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.dream.mecanism.sfx.ghost.DreamGhostManager; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +public class PlayerQuitListener implements Listener { + @EventHandler + public void onQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + DreamGhostManager.removeGhost(player); + + for (Player other : Bukkit.getOnlinePlayers()) { + other.showPlayer(OMCPlugin.getInstance(), player); + player.showPlayer(OMCPlugin.getInstance(), other); + } + } +} diff --git a/src/main/java/fr/openmc/core/utils/bukkit/ParticleUtils.java b/src/main/java/fr/openmc/core/utils/bukkit/ParticleUtils.java index 05ea86948..c43415c99 100644 --- a/src/main/java/fr/openmc/core/utils/bukkit/ParticleUtils.java +++ b/src/main/java/fr/openmc/core/utils/bukkit/ParticleUtils.java @@ -38,7 +38,9 @@ public class ParticleUtils { public static Color color1; public static Color color2; - // based on org.bukkit.craftbukkit.CraftParticle + /** + * based on {@link org.bukkit.craftbukkit.CraftParticle} + */ private static final Map> PARTICLE_FALLBACKS; static { @@ -113,9 +115,11 @@ public void run() { } public static void sendParticlePacket(Particle particle, Location loc, int radius) { - Collection players = loc.getNearbyEntitiesByType(Player.class, radius); + sendParticlePacket(particle, loc, loc.getNearbyEntitiesByType(Player.class, radius)); + } - for (Player player : players) { + public static void sendParticlePacket(Particle particle, Location loc, Collection receivers) { + for (Player player : receivers) { sendParticlePacket(player, particle, loc, 3, 0.2f, 0.2f, 0.2f, 0.01f, null); } } @@ -264,9 +268,9 @@ public void run() { }.runTaskTimerAsynchronously(OMCPlugin.getInstance(), 0L, 1L); } - 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 spawnCloudParticlesToAll(Location center, Particle particle, int count, double radiusCloud, double height, Collection receivers) { + for (Player player : receivers) { + spawnCloudParticles(player, particle, center, count, radiusCloud, height); } } From 8bf0f4ff0d40d920bccfcc5a35426ae109ac9704 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Thu, 4 Jun 2026 21:38:51 +0200 Subject: [PATCH 2/6] player ghost in NMS --- .../mecanism/sfx/ghost/DreamGhostManager.java | 88 +++++++++++-------- .../dream/mecanism/sfx/ghost/PlayerGhost.java | 5 ++ .../listeners/DreamPlayerEnteredListener.java | 3 +- .../openmc/core/utils/bukkit/SkullUtils.java | 3 +- .../fr/openmc/core/utils/nms/SkullNMS.java | 21 +++++ .../core/utils/nms/entity/ArmorStandNMS.java | 22 +++++ .../utils/nms/entity/EntityEquipmentNMS.java | 25 ++++++ .../utils/nms/entity/EntityRemoveNMS.java | 16 ++++ .../core/utils/nms/entity/EntitySpawnNMS.java | 43 +++++++++ .../utils/nms/entity/EntityTeleportNMS.java | 28 ++++++ 10 files changed, 215 insertions(+), 39 deletions(-) create mode 100644 src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/PlayerGhost.java create mode 100644 src/main/java/fr/openmc/core/utils/nms/SkullNMS.java create mode 100644 src/main/java/fr/openmc/core/utils/nms/entity/ArmorStandNMS.java create mode 100644 src/main/java/fr/openmc/core/utils/nms/entity/EntityEquipmentNMS.java create mode 100644 src/main/java/fr/openmc/core/utils/nms/entity/EntityRemoveNMS.java create mode 100644 src/main/java/fr/openmc/core/utils/nms/entity/EntitySpawnNMS.java create mode 100644 src/main/java/fr/openmc/core/utils/nms/entity/EntityTeleportNMS.java diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java index 5a2b81ac3..5b37a7177 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java @@ -5,15 +5,15 @@ import fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners.DreamPlayerEnteredListener; import fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners.PlayerQuitListener; import fr.openmc.core.utils.bukkit.ParticleUtils; -import fr.openmc.core.utils.bukkit.SkullUtils; +import fr.openmc.core.utils.nms.SkullNMS; +import fr.openmc.core.utils.nms.entity.*; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.ai.attributes.AttributeInstance; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.decoration.ArmorStand; import org.bukkit.*; -import org.bukkit.attribute.Attribute; -import org.bukkit.attribute.AttributeInstance; -import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.persistence.PersistentDataType; import org.bukkit.scheduler.BukkitRunnable; import java.util.Collection; @@ -27,8 +27,7 @@ * Cache tous les joueurs + met juste leur tete d'affiché avec particule */ public class DreamGhostManager { - private static final Map ghostStands = new HashMap<>(); - private static final NamespacedKey GHOST_KEY = new NamespacedKey(OMCPlugin.getInstance(), "ghost_stand"); + private static final Map playerGhost = new HashMap<>(); public static void init() { OMCPlugin.registerEvents( @@ -38,39 +37,38 @@ public static void init() { } public static void setupGhost(Player player) { - World world = player.getWorld(); - - for (Player other : world.getPlayers()) { - if (!other.equals(player)) { - other.hidePlayer(OMCPlugin.getInstance(), player); - player.hidePlayer(OMCPlugin.getInstance(), other); - } - } + int entityId = player.getEntityId() + 100000; - ArmorStand stand = (ArmorStand) world.spawnEntity(player.getLocation(), EntityType.ARMOR_STAND); - stand.setVisible(false); - stand.setGravity(false); - stand.setCustomNameVisible(false); - stand.setCanPickupItems(false); - stand.setMarker(false); - stand.getPersistentDataContainer().set(GHOST_KEY, PersistentDataType.BOOLEAN, true); + ArmorStand stand = ArmorStandNMS.createFakeStand(player, entityId, player.getLocation()); - AttributeInstance instance = stand.getAttribute(Attribute.SCALE); + AttributeInstance instance = stand.getAttribute(Attributes.SCALE); if (instance == null) return; - instance.setBaseValue(1.7); - ItemStack skull = SkullUtils.getPlayerSkull(player.getUniqueId()); - stand.getEquipment().setHelmet(skull); + playerGhost.put(player.getUniqueId(), new PlayerGhost(entityId, stand)); + + World world = player.getWorld(); + + for (Player other : world.getPlayers()) { + if (other.equals(player)) continue; + + other.hidePlayer(OMCPlugin.getInstance(), player); + player.hidePlayer(OMCPlugin.getInstance(), other); - ghostStands.put(player.getUniqueId(), stand); + sendGhostTo(other, player, entityId, stand); + + PlayerGhost otherGhost = playerGhost.get(other.getUniqueId()); + if (otherGhost != null) { + sendGhostTo(player, other, otherGhost.entityId(), otherGhost.stand()); + } + } new BukkitRunnable() { @Override public void run() { if (!player.isOnline() || !DreamUtils.isInDreamWorld(player) - || !ghostStands.containsKey(player.getUniqueId())) { + || !playerGhost.containsKey(player.getUniqueId())) { removeGhost(player); this.cancel(); return; @@ -89,20 +87,36 @@ public void run() { Particle.SHRIEK.builder() .location(newStand) - .data(20) + .data(10) .receivers(receivers) .spawn(); - stand.teleport(newStand); - player.hideEntity(OMCPlugin.getInstance(), stand); + for (Player other : player.getWorld().getPlayers()) { + if (!other.equals(player)) { + EntityTeleportNMS.sendTeleportPacket(other, entityId, player.getLocation()); + } + } } }.runTaskTimer(OMCPlugin.getInstance(), 0L, 2L); } + private static void sendGhostTo(Player receiver, Player ghostOf, int entityId, ArmorStand stand) { + EntitySpawnNMS.sendSpawnPacket(receiver, EntityType.ARMOR_STAND, entityId, stand.getUUID(), ghostOf.getLocation()); + EntitySpawnNMS.sendMetaDataEntity(receiver, stand); + EntityEquipmentNMS.sendHelmetPacket(receiver, entityId, SkullNMS.getPlayerSkullNMS(ghostOf)); + } + public static void removeGhost(Player player) { - ArmorStand stand = ghostStands.get(player.getUniqueId()); - if (stand == null) return; - stand.remove(); - ghostStands.remove(player.getUniqueId()); + PlayerGhost ghost = playerGhost.remove(player.getUniqueId()); + + if (ghost.stand() == null) return; + ghost.stand().remove(Entity.RemovalReason.DISCARDED); + + for (Player other : Bukkit.getOnlinePlayers()) { + if (other.equals(player)) continue; + EntityRemoveNMS.sendRemovePacket(other, ghost.entityId()); + other.showPlayer(OMCPlugin.getInstance(), player); + player.showPlayer(OMCPlugin.getInstance(), other); + } } } diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/PlayerGhost.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/PlayerGhost.java new file mode 100644 index 000000000..31714ef48 --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/PlayerGhost.java @@ -0,0 +1,5 @@ +package fr.openmc.core.features.dream.mecanism.sfx.ghost; + +import net.minecraft.world.entity.decoration.ArmorStand; + +public record PlayerGhost(int entityId, ArmorStand stand) {} diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java index 5c701f45c..8fe368a5e 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java @@ -13,7 +13,8 @@ public class DreamPlayerEnteredListener implements Listener { @EventHandler public void onDreamEnter(DreamEnterEvent event) { - DreamGhostManager.setupGhost(event.getPlayer()); + Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> + DreamGhostManager.setupGhost(event.getPlayer()), 20L); } @EventHandler diff --git a/src/main/java/fr/openmc/core/utils/bukkit/SkullUtils.java b/src/main/java/fr/openmc/core/utils/bukkit/SkullUtils.java index 820d96f17..4d890ad27 100644 --- a/src/main/java/fr/openmc/core/utils/bukkit/SkullUtils.java +++ b/src/main/java/fr/openmc/core/utils/bukkit/SkullUtils.java @@ -2,6 +2,7 @@ import com.destroystokyo.paper.profile.PlayerProfile; import com.destroystokyo.paper.profile.ProfileProperty; +import fr.openmc.core.utils.cache.CachePlayerProfile; import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.datacomponent.item.ResolvableProfile; import net.kyori.adventure.text.Component; @@ -27,7 +28,7 @@ public class SkullUtils { */ public static ItemStack getPlayerSkull(UUID playerUUID) { ItemStack skull = new ItemStack(Material.PLAYER_HEAD); - PlayerProfile profile = Bukkit.createProfile(playerUUID); + PlayerProfile profile = CachePlayerProfile.getPlayerProfile(playerUUID); skull.setData(DataComponentTypes.PROFILE, ResolvableProfile.resolvableProfile(profile)); return skull; } diff --git a/src/main/java/fr/openmc/core/utils/nms/SkullNMS.java b/src/main/java/fr/openmc/core/utils/nms/SkullNMS.java new file mode 100644 index 000000000..27848b685 --- /dev/null +++ b/src/main/java/fr/openmc/core/utils/nms/SkullNMS.java @@ -0,0 +1,21 @@ +package fr.openmc.core.utils.nms; + +import net.minecraft.core.component.DataComponents; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.component.ResolvableProfile; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class SkullNMS { + public static ItemStack getPlayerSkullNMS(Player player) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + ItemStack skull = new ItemStack(Items.PLAYER_HEAD); + + ResolvableProfile profile = ResolvableProfile.createResolved(nmsPlayer.getGameProfile()); + + skull.set(DataComponents.PROFILE, profile); + return skull; + } +} diff --git a/src/main/java/fr/openmc/core/utils/nms/entity/ArmorStandNMS.java b/src/main/java/fr/openmc/core/utils/nms/entity/ArmorStandNMS.java new file mode 100644 index 000000000..f3d8d56d4 --- /dev/null +++ b/src/main/java/fr/openmc/core/utils/nms/entity/ArmorStandNMS.java @@ -0,0 +1,22 @@ +package fr.openmc.core.utils.nms.entity; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.decoration.ArmorStand; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.Player; + +public class ArmorStandNMS { + + public static ArmorStand createFakeStand(Player playerOf, int entityId, Location loc) { + ServerLevel level = ((CraftWorld) playerOf.getWorld()).getHandle(); + + ArmorStand stand = new ArmorStand(level, loc.getX(), loc.getY(), loc.getZ()); + stand.setId(entityId); + stand.setInvisible(true); + stand.setNoGravity(true); + stand.setMarker(false); + + return stand; + } +} diff --git a/src/main/java/fr/openmc/core/utils/nms/entity/EntityEquipmentNMS.java b/src/main/java/fr/openmc/core/utils/nms/entity/EntityEquipmentNMS.java new file mode 100644 index 000000000..1f1eee862 --- /dev/null +++ b/src/main/java/fr/openmc/core/utils/nms/entity/EntityEquipmentNMS.java @@ -0,0 +1,25 @@ +package fr.openmc.core.utils.nms.entity; + +import com.mojang.datafixers.util.Pair; +import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.List; + +public class EntityEquipmentNMS { + + public static void sendHelmetPacket(Player receiver, int entityId, ItemStack itemStackNMS) { + ServerPlayer nmsReceiver = ((CraftPlayer) receiver).getHandle(); + + ClientboundSetEquipmentPacket packet = new ClientboundSetEquipmentPacket( + entityId, + List.of(Pair.of(EquipmentSlot.HEAD, itemStackNMS)) + ); + + nmsReceiver.connection.send(packet); + } +} diff --git a/src/main/java/fr/openmc/core/utils/nms/entity/EntityRemoveNMS.java b/src/main/java/fr/openmc/core/utils/nms/entity/EntityRemoveNMS.java new file mode 100644 index 000000000..35ea369f2 --- /dev/null +++ b/src/main/java/fr/openmc/core/utils/nms/entity/EntityRemoveNMS.java @@ -0,0 +1,16 @@ +package fr.openmc.core.utils.nms.entity; + +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.server.level.ServerPlayer; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class EntityRemoveNMS { + + public static void sendRemovePacket(Player receiver, int entityId) { + ServerPlayer nmsReceiver = ((CraftPlayer) receiver).getHandle(); + + ClientboundRemoveEntitiesPacket packet = new ClientboundRemoveEntitiesPacket(entityId); + nmsReceiver.connection.send(packet); + } +} diff --git a/src/main/java/fr/openmc/core/utils/nms/entity/EntitySpawnNMS.java b/src/main/java/fr/openmc/core/utils/nms/entity/EntitySpawnNMS.java new file mode 100644 index 000000000..c12bd0852 --- /dev/null +++ b/src/main/java/fr/openmc/core/utils/nms/entity/EntitySpawnNMS.java @@ -0,0 +1,43 @@ +package fr.openmc.core.utils.nms.entity; + +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.List; +import java.util.UUID; + +public class EntitySpawnNMS { + + public static void sendSpawnPacket(Player receiver, EntityType entityType, int entityId, UUID entityUUID, Location loc) { + ServerPlayer nmsReceiver = ((CraftPlayer) receiver).getHandle(); + + ClientboundAddEntityPacket packet = new ClientboundAddEntityPacket( + entityId, + entityUUID, + loc.getX(), loc.getY(), loc.getZ(), + loc.getPitch(), loc.getYaw(), + entityType, + 0, + Vec3.ZERO, + loc.getYaw() + ); + + nmsReceiver.connection.send(packet); + } + + public static void sendMetaDataEntity(Player receiver, Entity entity) { + List> dataValues = entity.getEntityData().getNonDefaultValues(); + if (dataValues == null || dataValues.isEmpty()) return; + ClientboundSetEntityDataPacket entityDataPacket = new ClientboundSetEntityDataPacket(entity.getId(), dataValues); + ((CraftPlayer) receiver).getHandle().connection.send(entityDataPacket); + } + +} diff --git a/src/main/java/fr/openmc/core/utils/nms/entity/EntityTeleportNMS.java b/src/main/java/fr/openmc/core/utils/nms/entity/EntityTeleportNMS.java new file mode 100644 index 000000000..2a9ba0cc0 --- /dev/null +++ b/src/main/java/fr/openmc/core/utils/nms/entity/EntityTeleportNMS.java @@ -0,0 +1,28 @@ +package fr.openmc.core.utils.nms.entity; + +import net.minecraft.network.protocol.game.ClientboundEntityPositionSyncPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.PositionMoveRotation; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +public class EntityTeleportNMS { + + public static void sendTeleportPacket(Player receiver, int entityId, Location loc) { + ServerPlayer nmsReceiver = ((CraftPlayer) receiver).getHandle(); + + ClientboundEntityPositionSyncPacket packet = new ClientboundEntityPositionSyncPacket( + entityId, + new PositionMoveRotation(new Vec3(loc.getX(), loc.getY(), loc.getZ()), + Vec3.ZERO, + loc.getYaw(), + loc.getPitch() + ), + false + ); + + nmsReceiver.connection.send(packet); + } +} From 47c16d5a72245374e11652781e1626065418624a Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Fri, 5 Jun 2026 17:43:53 +0200 Subject: [PATCH 3/6] change: player cannot pickup items for another player --- .../core/features/dream/DreamManager.java | 3 ++- .../listeners/dream/PlayerPickupListener.java | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerPickupListener.java 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 2937f27f8..a4982d16d 100644 --- a/src/main/java/fr/openmc/core/features/dream/DreamManager.java +++ b/src/main/java/fr/openmc/core/features/dream/DreamManager.java @@ -122,7 +122,8 @@ public Set getListeners() { new SingularityCraftListener(), new PlayerDreamStructureListener(), new PlayerFoodChangeListener(), - new DreamLootListener() + new DreamLootListener(), + new PlayerPickupListener() ); } diff --git a/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerPickupListener.java b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerPickupListener.java new file mode 100644 index 000000000..4511ce33a --- /dev/null +++ b/src/main/java/fr/openmc/core/features/dream/listeners/dream/PlayerPickupListener.java @@ -0,0 +1,27 @@ +package fr.openmc.core.features.dream.listeners.dream; + +import fr.openmc.core.features.dream.DreamUtils; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityPickupItemEvent; + +import java.util.UUID; + +public class PlayerPickupListener implements Listener { + + @EventHandler + public void onPickup(EntityPickupItemEvent event) { + if (!(event.getEntity() instanceof Player player)) return; + if (!DreamUtils.isInDreamWorld(player)) return; + + Item item = event.getItem(); + + UUID thrower = item.getThrower(); + + if (thrower != null && !thrower.equals(player.getUniqueId())) { + event.setCancelled(true); + } + } +} From f905858695a19e1bc67463c9eead44b3e30f177d Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sat, 6 Jun 2026 16:06:56 +0200 Subject: [PATCH 4/6] fix: ghost is null --- .../features/dream/mecanism/sfx/ghost/DreamGhostManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java index 5b37a7177..a372ab09b 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java @@ -107,6 +107,7 @@ private static void sendGhostTo(Player receiver, Player ghostOf, int entityId, A } public static void removeGhost(Player player) { + if (!playerGhost.containsKey(player.getUniqueId())) return; PlayerGhost ghost = playerGhost.remove(player.getUniqueId()); if (ghost.stand() == null) return; From 59d7e7b3b422790140fdb9ffaa0e4f833c71a914 Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sat, 6 Jun 2026 16:14:15 +0200 Subject: [PATCH 5/6] fix: ghost is null --- .../features/dream/mecanism/sfx/ghost/DreamGhostManager.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java index a372ab09b..668877483 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java @@ -67,8 +67,7 @@ public static void setupGhost(Player player) { @Override public void run() { if (!player.isOnline() - || !DreamUtils.isInDreamWorld(player) - || !playerGhost.containsKey(player.getUniqueId())) { + || !DreamUtils.isInDreamWorld(player)) { removeGhost(player); this.cancel(); return; @@ -114,7 +113,6 @@ public static void removeGhost(Player player) { ghost.stand().remove(Entity.RemovalReason.DISCARDED); for (Player other : Bukkit.getOnlinePlayers()) { - if (other.equals(player)) continue; EntityRemoveNMS.sendRemovePacket(other, ghost.entityId()); other.showPlayer(OMCPlugin.getInstance(), player); player.showPlayer(OMCPlugin.getInstance(), other); From af2434fd587cd2b952898710252ca971b083fa3c Mon Sep 17 00:00:00 2001 From: iambibi_ <89582596+iambibi@users.noreply.github.com> Date: Sat, 6 Jun 2026 16:51:30 +0200 Subject: [PATCH 6/6] fix: player can not see other players --- .../mecanism/sfx/ghost/DreamGhostManager.java | 24 ++++++++++++------- .../listeners/DreamPlayerEnteredListener.java | 13 ---------- .../ghost/listeners/PlayerQuitListener.java | 22 ----------------- 3 files changed, 15 insertions(+), 44 deletions(-) delete mode 100644 src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/PlayerQuitListener.java diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java index 668877483..bff143dce 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/DreamGhostManager.java @@ -1,9 +1,9 @@ package fr.openmc.core.features.dream.mecanism.sfx.ghost; import fr.openmc.core.OMCPlugin; +import fr.openmc.core.features.dream.DreamDimensionManager; import fr.openmc.core.features.dream.DreamUtils; import fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners.DreamPlayerEnteredListener; -import fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners.PlayerQuitListener; import fr.openmc.core.utils.bukkit.ParticleUtils; import fr.openmc.core.utils.nms.SkullNMS; import fr.openmc.core.utils.nms.entity.*; @@ -12,7 +12,10 @@ import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.decoration.ArmorStand; -import org.bukkit.*; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Particle; +import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; @@ -31,8 +34,7 @@ public class DreamGhostManager { public static void init() { OMCPlugin.registerEvents( - new DreamPlayerEnteredListener(), - new PlayerQuitListener() + new DreamPlayerEnteredListener() ); } @@ -52,8 +54,8 @@ public static void setupGhost(Player player) { for (Player other : world.getPlayers()) { if (other.equals(player)) continue; - other.hidePlayer(OMCPlugin.getInstance(), player); - player.hidePlayer(OMCPlugin.getInstance(), other); + hidePlayer(other, player); + hidePlayer(player, other); sendGhostTo(other, player, entityId, stand); @@ -112,10 +114,14 @@ public static void removeGhost(Player player) { if (ghost.stand() == null) return; ghost.stand().remove(Entity.RemovalReason.DISCARDED); - for (Player other : Bukkit.getOnlinePlayers()) { + for (Player other : DreamDimensionManager.DREAM_WORLD.getPlayers()) { + if (other.equals(player)) continue; + EntityRemoveNMS.sendRemovePacket(other, ghost.entityId()); - other.showPlayer(OMCPlugin.getInstance(), player); - player.showPlayer(OMCPlugin.getInstance(), other); } } + + public static void hidePlayer(Player receiver, Player toHide) { + EntityRemoveNMS.sendRemovePacket(receiver, toHide.getEntityId()); + } } diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java index 8fe368a5e..350fab35d 100644 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java +++ b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/DreamPlayerEnteredListener.java @@ -1,11 +1,9 @@ package fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners; import fr.openmc.core.OMCPlugin; -import fr.openmc.core.features.dream.events.DreamEndEvent; import fr.openmc.core.features.dream.events.DreamEnterEvent; import fr.openmc.core.features.dream.mecanism.sfx.ghost.DreamGhostManager; import org.bukkit.Bukkit; -import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -16,15 +14,4 @@ public void onDreamEnter(DreamEnterEvent event) { Bukkit.getScheduler().runTaskLater(OMCPlugin.getInstance(), () -> DreamGhostManager.setupGhost(event.getPlayer()), 20L); } - - @EventHandler - public void onDreamExit(DreamEndEvent event) { - Player player = event.getPlayer(); - DreamGhostManager.removeGhost(player); - - for (Player other : Bukkit.getOnlinePlayers()) { - other.showPlayer(OMCPlugin.getInstance(), player); - player.showPlayer(OMCPlugin.getInstance(), other); - } - } } diff --git a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/PlayerQuitListener.java b/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/PlayerQuitListener.java deleted file mode 100644 index e3161e440..000000000 --- a/src/main/java/fr/openmc/core/features/dream/mecanism/sfx/ghost/listeners/PlayerQuitListener.java +++ /dev/null @@ -1,22 +0,0 @@ -package fr.openmc.core.features.dream.mecanism.sfx.ghost.listeners; - -import fr.openmc.core.OMCPlugin; -import fr.openmc.core.features.dream.mecanism.sfx.ghost.DreamGhostManager; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerQuitEvent; - -public class PlayerQuitListener implements Listener { - @EventHandler - public void onQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - DreamGhostManager.removeGhost(player); - - for (Player other : Bukkit.getOnlinePlayers()) { - other.showPlayer(OMCPlugin.getInstance(), player); - player.showPlayer(OMCPlugin.getInstance(), other); - } - } -}