From 23472d5c3ab2fcb1fac43fdc638ccfa2e94d6293 Mon Sep 17 00:00:00 2001 From: Tobias de Bruijn Date: Wed, 26 May 2021 21:26:05 +0200 Subject: [PATCH] Github #10 part 2/2. - Switched from using 'server side' particles to client side - Version bump to 2.3.0 --- gradle.properties | 2 +- .../HighlightAreaOfEffectExecutor.java | 69 ++++++++++++++++++- 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/gradle.properties b/gradle.properties index 632da7b..ce303e0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ -pluginVersion = 2.2.4 +pluginVersion = 2.3.0 pluginGroup = nl.thedutchmc.harotorch pluginName = HaroTorch \ No newline at end of file diff --git a/src/main/java/nl/thedutchmc/harotorch/commands/torchSubCmds/HighlightAreaOfEffectExecutor.java b/src/main/java/nl/thedutchmc/harotorch/commands/torchSubCmds/HighlightAreaOfEffectExecutor.java index 74c533e..a9f03b3 100644 --- a/src/main/java/nl/thedutchmc/harotorch/commands/torchSubCmds/HighlightAreaOfEffectExecutor.java +++ b/src/main/java/nl/thedutchmc/harotorch/commands/torchSubCmds/HighlightAreaOfEffectExecutor.java @@ -9,12 +9,14 @@ import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.World; +import org.bukkit.Particle.DustOptions; import org.bukkit.World.Environment; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; +import dev.array21.bukkitreflectionlib.ReflectionUtil; import net.md_5.bungee.api.ChatColor; import nl.thedutchmc.harotorch.HaroTorch; import nl.thedutchmc.harotorch.lang.LangHandler; @@ -24,6 +26,25 @@ public class HighlightAreaOfEffectExecutor { private static HashMap lastCommandTimestamps = new HashMap<>(); + private static Class packetPlayOutWorldParticleClass; + private static Class packetPlayOutWorldParticleInterfaceClass; + private static Class craftPlayerClass; + private static Class craftParticleClass; + private static Class particleParamClass; + + static { + try { + packetPlayOutWorldParticleClass = ReflectionUtil.getNmsClass("PacketPlayOutWorldParticles"); + packetPlayOutWorldParticleInterfaceClass = packetPlayOutWorldParticleClass.getInterfaces()[0]; + + craftPlayerClass = ReflectionUtil.getBukkitClass("entity.CraftPlayer"); + craftParticleClass = ReflectionUtil.getBukkitClass("CraftParticle"); + particleParamClass = ReflectionUtil.getNmsClass("ParticleParam"); + } catch(Exception e) { + e.printStackTrace(); + } + } + public static boolean aoe(CommandSender sender, HaroTorch plugin) { Integer commandCooldown = HaroTorch.getConfigHandler().commandCooldown; @@ -87,20 +108,23 @@ public void run() { final Location torchLoc = torchParticle.getTorch(); - torchLoc.getWorld().spawnParticle(Particle.REDSTONE, torchLoc.getX() + 0.5D, torchLoc.getY() + 1.5D, torchLoc.getZ() + 0.5D, 25, 0D, 0D, 0D, 0.005, new Particle.DustOptions(torchParticle.getTorchParticleColor(), 1)); + List particlePackets = new ArrayList<>(); + particlePackets.add(getParticlePacket(torchLoc.getX() + 0.5d, torchLoc.getY() + 1.5d, torchLoc.getZ() + 0.5d, 0f, 0f, 0f, 0.005f, 10, false, new Particle.DustOptions(torchParticle.getTorchParticleColor(), 1))); for(Location l : torchParticle.getCircleLocations()) { for(int i = 0; i < HaroTorch.getConfigHandler().torchAoeParticleHeight; i++) { - torchLoc.getWorld().spawnParticle(Particle.REDSTONE, l.getX() + 0.5D, l.getY() + 0.5D + i, l.getZ() + 0.5D, 5, 0D, 0D, 0D, 0.005, new Particle.DustOptions(torchParticle.getTorchParticleColor(), 1)); + particlePackets.add(getParticlePacket(l.getX() + 0.5d, l.getY() + 0.5d + i, l.getZ() + 0.5d, 0f, 0f, 0f, 0.005f, 5, false, new Particle.DustOptions(torchParticle.getTorchParticleColor(), 1))); } if(torchLoc.getWorld().getEnvironment() == Environment.NETHER) { for(int i = 1; i < HaroTorch.getConfigHandler().torchAoeParticleHeight -1; i++) { - torchLoc.getWorld().spawnParticle(Particle.REDSTONE, l.getX() + 0.5D, l.getY() + 0.5D - i, l.getZ() + 0.5D, 5, 0D, 0D, 0D, 0.005, new Particle.DustOptions(torchParticle.getTorchParticleColor(), 1)); + particlePackets.add(getParticlePacket(l.getX() + 0.5d, l.getY() + 0.5d - i, l.getZ() + 0.5d, 0f, 0f, 0f, 0.005f, 5, false, new Particle.DustOptions(torchParticle.getTorchParticleColor(), 1))); } } } + + spawnParticles(particlePackets, (Player) sender); } } @@ -118,6 +142,45 @@ public void run() { return true; } + private static Object getParticlePacket(double pX, double pY, double pZ, float oX, float oY, float oZ, float extra, int count, boolean force, DustOptions dustOptions) { + try { + Object nmsParticleData = particleDataToNms(Particle.REDSTONE, dustOptions); + Object particlePacket = ReflectionUtil.invokeConstructor(packetPlayOutWorldParticleClass, + new Class[] { particleParamClass, boolean.class, double.class, double.class, double.class, float.class, float.class, float.class, float.class, int.class}, + new Object[] { nmsParticleData, force, pX, pY, pZ, oX, oY, oZ, extra, count }); + + return particlePacket; + } catch(Exception e) { + e.printStackTrace(); + return null; + } + } + + private static void spawnParticles(List particlePackets, Player player) { + try { + Object entityPlayerObject = ReflectionUtil.invokeMethod(craftPlayerClass, player, "getHandle"); + Object playerConnectionObject = ReflectionUtil.getObject(entityPlayerObject, "playerConnection"); + + for(Object packet : particlePackets) { + ReflectionUtil.invokeMethod(playerConnectionObject, "sendPacket", + new Class[] { packetPlayOutWorldParticleInterfaceClass }, + new Object[] { packet }); + } + } catch(Exception e) { + e.printStackTrace(); + } + } + + private static Object particleDataToNms(Particle a, DustOptions b) { + try { + Object dataAsNMS = ReflectionUtil.invokeMethod(craftParticleClass, null, "toNMS", new Class[] { Particle.class, Object.class}, new Object[] {a, b}); + return dataAsNMS; + } catch(Exception e) { + e.printStackTrace(); + return null; + } + } + private static class TorchParticleObject { private Color particleColor;