From 054299d4acf6dfd99028f262b02ddd0538e19915 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Thu, 11 Jul 2013 20:54:06 +0300 Subject: [PATCH] Add ParticleEffect library. Allow all of its particles to be used by the Playeffect command. --- .../net/aufdemrand/denizen/objects/aH.java | 6 +- .../commands/world/PlayEffectCommand.java | 37 +-- .../containers/core/WorldScriptHelper.java | 5 +- .../denizen/utilities/ParticleEffect.java | 267 ++++++++++++++++++ 4 files changed, 286 insertions(+), 29 deletions(-) create mode 100644 src/main/java/net/aufdemrand/denizen/utilities/ParticleEffect.java diff --git a/src/main/java/net/aufdemrand/denizen/objects/aH.java b/src/main/java/net/aufdemrand/denizen/objects/aH.java index 5fa164b306..db9dff6b40 100644 --- a/src/main/java/net/aufdemrand/denizen/objects/aH.java +++ b/src/main/java/net/aufdemrand/denizen/objects/aH.java @@ -487,8 +487,7 @@ public static String getStringFrom(String arg) { @Deprecated public static Duration getDurationFrom(String arg) { - if (arg.split(":").length > 1) - arg = arg.split(":")[1]; + arg = arg.replace("duration:", "").replace("delay:", ""); return Duration.valueOf(arg); } @@ -498,8 +497,7 @@ public static boolean matchesDouble(String arg) { @Deprecated public static boolean matchesDuration(String arg) { - if (arg.split(":").length > 1) - arg = arg.split(":")[1]; + arg = arg.replace("duration:", "").replace("delay:", ""); return Duration.matches(arg); } diff --git a/src/main/java/net/aufdemrand/denizen/scripts/commands/world/PlayEffectCommand.java b/src/main/java/net/aufdemrand/denizen/scripts/commands/world/PlayEffectCommand.java index c60f50c21d..e4c2e0881f 100644 --- a/src/main/java/net/aufdemrand/denizen/scripts/commands/world/PlayEffectCommand.java +++ b/src/main/java/net/aufdemrand/denizen/scripts/commands/world/PlayEffectCommand.java @@ -1,9 +1,6 @@ package net.aufdemrand.denizen.scripts.commands.world; import org.bukkit.Effect; -import org.bukkit.EntityEffect; -import org.bukkit.craftbukkit.v1_6_R2.entity.CraftWolf; -import org.bukkit.entity.Wolf; import net.aufdemrand.denizen.exceptions.CommandExecutionException; import net.aufdemrand.denizen.exceptions.InvalidArgumentsException; @@ -14,10 +11,14 @@ import net.aufdemrand.denizen.scripts.commands.AbstractCommand; import net.aufdemrand.denizen.utilities.debugging.dB; import net.aufdemrand.denizen.utilities.debugging.dB.Messages; +import net.aufdemrand.denizen.utilities.ParticleEffect; /* playeffect [location:] [effect:] (data:<#>) (radius:<#>)*/ /** + * Lets you play a Bukkit effect or a ParticleEffect from the + * ParticleEffect Library at a certain location. + * * Arguments: [] - Required, () - Optional * [location:] specifies location of the effect * [effect:] sets the name of effect to be played @@ -33,9 +34,6 @@ public class PlayEffectCommand extends AbstractCommand { - // Implement some special effects that are not in Bukkit's Effect class - private enum SpecialEffect { HEARTS, EXPLOSION } - @Override public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException { @@ -54,14 +52,14 @@ public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException if (arg.matchesEnum(Effect.values())) { scriptEntry.addObject("effect", Effect.valueOf(arg.getValue().toUpperCase())); } - else if (arg.matchesEnum(SpecialEffect.values())) { - scriptEntry.addObject("specialeffect", SpecialEffect.valueOf(arg.getValue().toUpperCase())); + else if (arg.matchesEnum(ParticleEffect.values())) { + scriptEntry.addObject("specialeffect", ParticleEffect.valueOf(arg.getValue().toUpperCase())); } } else if (!scriptEntry.hasObject("radius") - && arg.matchesPrimitive(aH.PrimitiveType.Integer) - && arg.matchesPrefix("radius, r")) { + && arg.matchesPrimitive(aH.PrimitiveType.Double) + && arg.matchesPrefix("range, radius, r")) { // Add value scriptEntry.addObject("radius", arg.asElement()); } @@ -99,7 +97,7 @@ public void execute(ScriptEntry scriptEntry) throws CommandExecutionException { // Extract objects from ScriptEntry dLocation location = (dLocation) scriptEntry.getObject("location"); Effect effect = (Effect) scriptEntry.getObject("effect"); - SpecialEffect specialEffect = (SpecialEffect) scriptEntry.getObject("specialeffect"); + ParticleEffect particleEffect = (ParticleEffect) scriptEntry.getObject("specialeffect"); Element radius = (Element) scriptEntry.getObject("radius"); Element data = (Element) scriptEntry.getObject("data"); @@ -107,7 +105,7 @@ public void execute(ScriptEntry scriptEntry) throws CommandExecutionException { dB.report(getName(), (effect != null ? aH.debugObj("effect", effect.name()) : - aH.debugObj("special effect", specialEffect.name())) + + aH.debugObj("special effect", particleEffect.name())) + aH.debugObj("location", location.toString() + aH.debugObj("radius", radius) + aH.debugObj("data", data))); @@ -118,18 +116,9 @@ public void execute(ScriptEntry scriptEntry) throws CommandExecutionException { } // Play one of the special effects else { - if (specialEffect.equals(SpecialEffect.HEARTS)) { - - Wolf wolf = (Wolf) location.getWorld().spawn(location, Wolf.class); - ((CraftWolf) wolf).getHandle().setInvisible(true); - wolf.playEffect(EntityEffect.WOLF_HEARTS); - wolf.remove(); - } - else if (specialEffect.equals(SpecialEffect.EXPLOSION)) { - - location.getWorld().createExplosion(location, 0); - } + ParticleEffect.fromName(particleEffect.name()) + .play(location, radius.asDouble(), + 1.0F, 1.0F, 1.0F, 1.0F, 3); } } - } diff --git a/src/main/java/net/aufdemrand/denizen/scripts/containers/core/WorldScriptHelper.java b/src/main/java/net/aufdemrand/denizen/scripts/containers/core/WorldScriptHelper.java index ba6febec16..52f0c83bb4 100644 --- a/src/main/java/net/aufdemrand/denizen/scripts/containers/core/WorldScriptHelper.java +++ b/src/main/java/net/aufdemrand/denizen/scripts/containers/core/WorldScriptHelper.java @@ -487,6 +487,8 @@ public void entityExplode(EntityExplodeEvent event) { Map context = new HashMap(); Entity entity = event.getEntity(); + if (entity == null) return; + context.put("entity", new dEntity(entity)); context.put("location", new dLocation(event.getLocation())); @@ -1079,11 +1081,12 @@ public void playerMoveEvent(PlayerMoveEvent event) { if (name != null) { Map context = new HashMap(); - context.put("notable_name", new Element(name)); + context.put("notable", new Element(name)); String determination = doEvents(Arrays.asList ("player walks over notable", "player walks over " + name, + "walked over notable", "walked over " + name), null, event.getPlayer(), context); diff --git a/src/main/java/net/aufdemrand/denizen/utilities/ParticleEffect.java b/src/main/java/net/aufdemrand/denizen/utilities/ParticleEffect.java new file mode 100644 index 0000000000..1812a9ea77 --- /dev/null +++ b/src/main/java/net/aufdemrand/denizen/utilities/ParticleEffect.java @@ -0,0 +1,267 @@ +package net.aufdemrand.denizen.utilities; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +/** +* ParticleEffect Library v1.0 +* +* This particle effect library was created by DarkBlade12 based off content from microgeek +* You are free to use it, modify it and redistribute it under the condition to give credit to me and microgeek +* +* @author DarkBlade12 +*/ +public enum ParticleEffect { + + HUGE_EXPLOSION("hugeexplosion", 0), + LARGE_EXPLODE("largeexplode", 1), + FIREWORKS_SPARK("fireworksSpark", 2), + BUBBLE("bubble", 3), + SUSPEND("suspend", 4), + DEPTH_SUSPEND("depthSuspend", 5), + TOWN_AURA("townaura", 6), + CRIT("crit", 7), + MAGIC_CRIT("magicCrit", 8), + MOB_SPELL("mobSpell", 9), + MOB_SPELL_AMBIENT("mobSpellAmbient", 10), + SPELL("spell", 11), + INSTANT_SPELL("instantSpell", 12), + WITCH_MAGIC("witchMagic", 13), + NOTE("note", 14), + PORTAL("portal", 15), + ENCHANTMENT_TABLE("enchantmenttable", 16), + EXPLODE("explode", 17), + FLAME("flame", 18), + LAVA("lava", 19), + FOOTSTEP("footstep", 20), + SPLASH("splash", 21), + LARGE_SMOKE("largesmoke", 22), + CLOUD("cloud", 23), + RED_DUST("reddust", 24), + SNOWBALL_POOF("snowballpoof", 25), + DRIP_WATER("dripWater", 26), + RIP_LAVA("dripLava", 27), + SNOW_SHOVEL("snowshovel", 28), + SLIME("slime", 29), + HEART("heart", 30), + ANGRY_VILLAGER("angryVillager", 31), + HAPPY_VILLAGER("happyVillager", 32); + + private String name; + private int id; + + ParticleEffect(String name, int id) { + this.name = name; + this.id = id; + } + + public String getName() { + return name; + } + + public int getId() { + return id; + } + + private static final Map NAME_MAP = new HashMap(); + private static final Map ID_MAP = new HashMap(); + static { + for (ParticleEffect effect : values()) { + NAME_MAP.put(effect.name, effect); + ID_MAP.put(effect.id, effect); + } + } + + public static ParticleEffect fromName(String name) { + if (name == null) { + return null; + } + for (Entry e : NAME_MAP.entrySet()) { + if (e.getKey().equalsIgnoreCase(name)) { + return e.getValue(); + } + } + return null; + } + + public static ParticleEffect fromId(int id) { + return ID_MAP.get(id); + } + + /** + * Plays a particle effect at a location which is only shown to a specific player. + */ + public void play(Player p, Location loc, float offsetX, float offsetY, float offsetZ, float speed, int amount) { + sendPacket(p, createNormalPacket(this, loc, offsetX, offsetY, offsetZ, speed, amount)); + } + + /** + * Plays a particle effect at a location which is shown to all players in the current world. + */ + public void play(Location loc, float offsetX, float offsetY, float offsetZ, float speed, int amount) { + Object packet = createNormalPacket(this, loc, offsetX, offsetY, offsetZ, speed, amount); + for (Player p : loc.getWorld().getPlayers()) { + sendPacket(p, packet); + } + } + + /** + * Plays a particle effect at a location which is shown to all players within a certain range in the current world. + */ + public void play(Location loc, double range, float offsetX, float offsetY, float offsetZ, float speed, int amount) { + Object packet = createNormalPacket(this, loc, offsetX, offsetY, offsetZ, speed, amount); + for (Player p : loc.getWorld().getPlayers()) { + if (p.getLocation().distance(loc) <= range) { + sendPacket(p, packet); + } + } + } + + /** + * Plays a tilecrack effect at a location which is only shown to a specific player. + */ + public static void playTileCrack(Player p, Location loc, int id, byte data, float offsetX, float offsetY, float offsetZ, int amount) { + sendPacket(p, createTileCrackPacket(id, data, loc, offsetX, offsetY, offsetZ, amount)); + } + + /** + * Plays a tilecrack effect at a location which is shown to all players in the current world. + */ + public static void playTileCrack(Location loc, int id, byte data, float offsetX, float offsetY, float offsetZ, int amount) { + Object packet = createTileCrackPacket(id, data, loc, offsetX, offsetY, offsetZ, amount); + for (Player p : loc.getWorld().getPlayers()) { + sendPacket(p, packet); + } + } + + /** + * Plays a tilecrack effect at a location which is shown to all players within a certain range in the current world. + */ + public static void playTileCrack(Location loc, double range, int id, byte data, float offsetX, float offsetY, float offsetZ, int amount) { + Object packet = createTileCrackPacket(id, data, loc, offsetX, offsetY, offsetZ, amount); + for (Player p : loc.getWorld().getPlayers()) { + if (p.getLocation().distance(loc) <= range) { + sendPacket(p, packet); + } + } + } + + /** + * Plays an iconcrack effect at a location which is only shown to a specific player. + */ + public static void playIconCrack(Player p, Location loc, int id, float offsetX, float offsetY, float offsetZ, int amount) { + sendPacket(p, createIconCrackPacket(id, loc, offsetX, offsetY, offsetZ, amount)); + } + + /** + * Plays an iconcrack effect at a location which is shown to all players in the current world. + */ + public static void playIconCrack(Location loc, int id, float offsetX, float offsetY, float offsetZ, int amount) { + Object packet = createIconCrackPacket(id, loc, offsetX, offsetY, offsetZ, amount); + for (Player p : loc.getWorld().getPlayers()) { + sendPacket(p, packet); + } + } + + /** + * Plays an iconcrack effect at a location which is shown to all players within a certain range in the current world. + */ + public static void playIconCrack(Location loc, double range, int id, float offsetX, float offsetY, float offsetZ, int amount) { + Object packet = createIconCrackPacket(id, loc, offsetX, offsetY, offsetZ, amount); + for (Player p : loc.getWorld().getPlayers()) { + if (p.getLocation().distance(loc) <= range) { + sendPacket(p, packet); + } + } + } + + private Object createNormalPacket(ParticleEffect effect, Location loc, float offsetX, float offsetY, float offsetZ, float speed, int amount) { + return createPacket(effect.getName(), loc, offsetX, offsetY, offsetZ, speed, amount); + } + + private static Object createTileCrackPacket(int id, byte data, Location loc, float offsetX, float offsetY, float offsetZ, int amount) { + return createPacket("tilecrack_" + id + "_" + data, loc, offsetX, offsetY, offsetZ, 0.1F, amount); + } + + private static Object createIconCrackPacket(int id, Location loc, float offsetX, float offsetY, float offsetZ, int amount) { + return createPacket("iconcrack_" + id, loc, offsetX, offsetY, offsetZ, 0.1F, amount); + } + + private static Object createPacket(String effectName, Location loc, float offsetX, float offsetY, float offsetZ, float speed, int amount) { + try { + if (amount <= 0) { + throw new IllegalArgumentException("Amount of particles has to be greater than 0!"); + } + Object packet = ReflectionUtil.getClass("Packet63WorldParticles"); + ReflectionUtil.setValue(packet, "a", effectName); + ReflectionUtil.setValue(packet, "b", (float) loc.getX()); + ReflectionUtil.setValue(packet, "c", (float) loc.getY()); + ReflectionUtil.setValue(packet, "d", (float) loc.getZ()); + ReflectionUtil.setValue(packet, "e", offsetX); + ReflectionUtil.setValue(packet, "f", offsetY); + ReflectionUtil.setValue(packet, "g", offsetZ); + ReflectionUtil.setValue(packet, "h", speed); + ReflectionUtil.setValue(packet, "i", amount); + return packet; + } catch (Exception e) { + Bukkit.getLogger().warning("[ParticleEffect] Failed to create a particle packet!"); + return null; + } + } + + private static void sendPacket(Player p, Object packet) { + if (packet == null) { + return; + } + try { + Object entityPlayer = ReflectionUtil.getMethod("getHandle", p.getClass(), 0).invoke(p); + Object playerConnection = entityPlayer.getClass().getField("playerConnection").get(entityPlayer); + ReflectionUtil.getMethod("sendPacket", playerConnection.getClass(), 1).invoke(playerConnection, packet); + } catch (Exception e) { + Bukkit.getLogger().warning("[ParticleEffect] Failed to send a particle packet to " + p.getName() + "!"); + } + } + + private static class ReflectionUtil { + public static Object getClass(String name, Object... args) throws Exception { + Class c = Class.forName(ReflectionUtil.getPackageName() + "." + name); + int params = 0; + if (args != null) { + params = args.length; + } + for (Constructor co : c.getConstructors()) { + if (co.getParameterTypes().length == params) { + return co.newInstance(args); + } + } + return null; + } + + public static Method getMethod(String name, Class c, int params) { + for (Method m : c.getMethods()) { + if (m.getName().equals(name) && m.getParameterTypes().length == params) { + return m; + } + } + return null; + } + + public static void setValue(Object instance, String fieldName, Object value) throws Exception { + Field field = instance.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(instance, value); + } + + public static String getPackageName() { + return "net.minecraft.server." + Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + } + } +} \ No newline at end of file