├── .github
├── FUNDING.yml
└── stale.yml
├── .travis.yml
├── pom.xml
├── renovate.json
├── settings.xml
└── src
└── main
├── java
├── de
│ └── inventivegames
│ │ └── particle
│ │ └── ParticleEffect.java
└── org
│ └── inventivetalent
│ └── particle
│ ├── ParticleEffect.java
│ ├── ParticleException.java
│ └── ParticlePlugin.java
└── resources
└── plugin.yml
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: InventivetalentDev
2 | patreon: inventivetalent
3 | custom: ["https://www.paypal.me/inventivetalent", "https://donation.inventivetalent.org"]
4 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk8
4 |
5 | script: "mvn deploy --settings settings.xml"
6 | env:
7 | global:
8 | - secure: "IZ3oqCMkToBV7Pv5vfj5R86JpL422+grm56mI+BPO2e+7NPil9qfh0Gw5Z7rpQuH3pURgk37xcLF/E5PsSKJiBVXaoWvyQUczIYE3e3NhyQCJ4mtXSZ0dXpvdqQunAPhqcw5MZpKiI03rqOJbJTLvBX0J5aMOQM3pW9R5J5S/B/fgQXclvbR1u09UdUU6j0+Y8Jky1pyl9R9E7mJZMHvbXnAvPgbHyBncOiY58vZSA9s0Q4C05nH35S1THj7Nb2uZsm0Y1gjCyPYGz3YGna/4uwVIr3Lc1x/BzPXryryhf8x+2SNicZHNMyEhvHHkstlexeA28iaPCHqAxMvLV/OraZhE2yhbg1WvfkdQafnLRmR08+mXuQoP+APnzM1uYosf27FAKUC59UWOKaITvQQj47dccN3MNVTEKsZ+aqA0PX88lAGPXePlsymEEZxj6FAeCfX3jAWfZ4zUhHoldzF/Id+d/loN+0d8AuOVopnK4kPNhKThsgc7vmWVzKKpvCJ5QC6+isaROHcC8dw6fTxk2sLBypPyu8yRgIRZmWFdCV+TPL8IgZTdscnyUOwbODcpAERG3WNPATId85QnNwVY1CRizNzdznbo2VTf2EivKMjTCxZFzOe+EGEEGcAAviJITNe+mEDHiCN4RK3BPk3x7+MynIVzZJymOd39/BKHlY="
9 | - secure: "xi/uz84SwYXyrnQAO+7o7PkeIS7vKilwLYOC13fewuoVAT/tSXFal945O1VA7kLshnpoZ+oKijfne6J7GJEBceRqGPEQ88gkqkF+6A7Isf/k/07dNIBlOIU6FNHeLcdslM+ahrbAqXolhuHq3p3cXzEhD8JLS2E6EVaTrlUOFpejFlkXrQnetSiymmCRhV4yZ62PKxZNUwRM49OKHKrHcF/TOBTQLsWuGwPv9AMrV++SqhwbTDzlKHibNqtyGOsygnreL6qPv10BjZoOrQ7df4qnKJTEMlY+VqoZvXBfQczNX0CzpIm0ZzTcZ2JxabUSxlRhutPAkTFKt0VfvDFV0zMeIToUNev8IUBCRGuqAz1vgtkdPk+0QRqFYRCYqR3T5j/eqU0R8K17l8kfE//qtpeNDBgZ91o1LnXxDZH9LiFJNn78JpHQvXLg2twGd7hy48mjbD0ogd81rLxgtRG3z1p6NCIA7qqiM4fk/om5WZxeSjpmNUzX4qyNq2OYoNtnvQ9mjj3TH8nQ4n1pmP18bCULTI1ZiTfSgkaKwZVDjN6v4nts42qBRXfVKCtHmRBZ+jT7mrb4FJgcz6D97kz2VFmhTUyIzBcBDaWF7YDw/REYh3mWZ3jxYSy6AUQM6aoaFNJnMFXsBra9azp0WwfiNvYCa9c9zpWr86Y3nxO6KzQ="
10 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
28 |
29 |
31 | 4.0.0
32 | org.inventivetalent
33 | particleapi
34 | 2.1.2
35 | ParticleAPI
36 |
37 |
38 | ParticleAPI_v${project.version}
39 | src/main/java
40 |
41 |
42 | src/main/java
43 |
44 | **/*.java
45 |
46 |
47 |
48 | src/main/resources
49 | true
50 |
51 | plugin.yml
52 | config.yml
53 |
54 |
55 |
56 |
57 |
58 | maven-compiler-plugin
59 | 3.3
60 |
61 | 1.7
62 | 1.7
63 |
64 |
65 |
66 | org.apache.maven.plugins
67 | maven-shade-plugin
68 | 2.4
69 |
70 |
71 | package
72 |
73 | shade
74 |
75 |
76 |
77 |
78 | org.mcstats.*
79 | org.inventivetalent:particleapi**
80 | org.inventivetalent:apimanager**
81 | org.inventivetalent:reflectionhelper**
82 |
83 |
84 |
85 |
86 | org.mcstats
87 | org.inventivetalent.particle.mcstats
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | sonatype-nexus-releases
99 | http://repo.inventivetalent.org/content/repositories/releases/
100 |
101 |
102 | sonatype-nexus-snapshots
103 | http://repo.inventivetalent.org/content/repositories/snapshots/
104 |
105 |
106 |
107 |
108 | org.spigotmc
109 | spigot-api
110 | 1.11-R0.1-SNAPSHOT
111 | provided
112 |
113 |
114 | org.inventivetalent
115 | reflectionhelper
116 | LATEST
117 |
118 |
119 |
120 |
121 |
122 | inventive-repo
123 | https://repo.inventivetalent.org/content/groups/public/
124 |
125 |
126 | md_5-repo
127 | http://repo.md-5.net/content/repositories/public/
128 |
129 |
130 | sonatype
131 | https://oss.sonatype.org/content/groups/public/
132 |
133 |
134 | spigot-repo
135 | https://hub.spigotmc.org/nexus/content/groups/public/
136 |
137 |
138 | sk89q-repo
139 | http://maven.sk89q.com/artifactory/repo/
140 |
141 |
142 | techcable-repo
143 | http://repo.techcable.net/content/groups/public/
144 |
145 |
146 | mcstats-repo
147 | http://repo.mcstats.org/content/groups/public/
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base"
4 | ],
5 | "maven": {
6 | "enabled": true
7 | },
8 | "ignoreUnstable": false,
9 | "hostRules": [{
10 | "hostType": "maven",
11 | "endpoint": "https://repo.inventivetalent.org/content/groups/public/"
12 | }]
13 | }
14 |
--------------------------------------------------------------------------------
/settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | sonatype-nexus-releases
5 | ${env.CI_DEPLOY_USERNAME}
6 | ${env.CI_DEPLOY_PASSWORD}
7 |
8 |
9 | sonatype-nexus-snapshots
10 | ${env.CI_DEPLOY_USERNAME}
11 | ${env.CI_DEPLOY_PASSWORD}
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/main/java/de/inventivegames/particle/ParticleEffect.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 inventivetalent. All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without modification, are
5 | * permitted provided that the following conditions are met:
6 | *
7 | * 1. Redistributions of source code must retain the above copyright notice, this list of
8 | * conditions and the following disclaimer.
9 | *
10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 | * of conditions and the following disclaimer in the documentation and/or other materials
12 | * provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 | *
24 | * The views and conclusions contained in the software and documentation are those of the
25 | * authors and contributors and should not be interpreted as representing official policies,
26 | * either expressed or implied, of anybody else.
27 | */
28 |
29 | package de.inventivegames.particle;
30 |
31 | import org.bukkit.Bukkit;
32 | import org.bukkit.Location;
33 | import org.bukkit.entity.Player;
34 |
35 | import java.lang.reflect.Field;
36 | import java.lang.reflect.Method;
37 | import java.util.Collection;
38 |
39 | /**
40 | * @deprecated Please use org.inventivetalent.particle.ParticleEffect to get support for 1.9+ Particles
41 | */
42 | @Deprecated
43 | public enum ParticleEffect {
44 |
45 | // == Support for 1.7 Implementation ==
46 | HUGE_EXPLOSION("hugeexplosion", "EXPLOSION_HUGE"),
47 | LARGE_EXPLODE("largeexplode", "EXPLOSION_LARGE"),
48 | BUBBLE("bubble", "WATER_BUBBLE"),
49 | SUSPEND("suspended", "SUSPENDED"),
50 | DEPTH_SUSPEND("depthsuspend", "SUSPENDED_DEPTH"),
51 | MAGIC_CRIT("magicCrit", "CRIT_MAGIC"),
52 | MOB_SPELL("mobSpell", "SPELL_MOB", true),
53 | MOB_SPELL_AMBIENT("mobSpellAmbient", "SPELL_MOB_AMBIENT"),
54 | INSTANT_SPELL("instantSpell", "SPELL_INSTANT"),
55 | WITCH_MAGIC("witchMagic", "SPELL_WITCH"),
56 | EXPLODE("explode", "EXPLOSION_NORMAL"),
57 | SPLASH("splash", "WATER_SPLASH"),
58 | LARGE_SMOKE("largesmoke", "SMOKE_LARGE"),
59 | /**
60 | * - Colored
61 | */
62 | RED_DUST("reddust", "REDSTONE", true),
63 | SNOWBALL_POOF("snowballpoof", "SNOWBALL"),
64 | ANGRY_VILLAGER("angryVillager", "VILLAGER_ANGRY"),
65 | HAPPY_VILLAGER("happyVillager", "VILLAGER_HAPPY"),
66 | // == 1.8 Particles and Supported 1.7 Particles ==
67 | /**
68 | * @see #EXPLODE
69 | */
70 | EXPLOSION_NORMAL(EXPLODE.getName()),
71 | /**
72 | * @see #LARGE_EXPLODE
73 | */
74 | EXPLOSION_LARGE(LARGE_EXPLODE.getName()),
75 | /**
76 | * 1.8 only!
77 | *
78 | * @see #HUGE_EXPLOSION
79 | */
80 | EXPLOSION_HUGE(HUGE_EXPLOSION.getName()),
81 | FIREWORKS_SPARK("fireworksSpark"),
82 | /**
83 | * @see #BUBBLE
84 | */
85 | WATER_BUBBLE(BUBBLE.getName()),
86 | /**
87 | * @see #SPLASH
88 | */
89 | WATER_SPLASH(SPLASH.getName()),
90 | /**
91 | * 1.8 only
92 | */
93 | WATER_WAKE("wake"),
94 | /**
95 | * @see #SUSPEND
96 | */
97 | SUSPENDED(SUSPEND.getName()),
98 | /**
99 | * @see #DEPTH_SUSPEND
100 | */
101 | SUSPENDED_DEPTH(DEPTH_SUSPEND.getName()),
102 | CRIT("crit"),
103 | /**
104 | * @see #MAGIC_CRIT
105 | */
106 | CRIT_MAGIC(MAGIC_CRIT.getName()),
107 | /**
108 | * 1.8 only!
109 | */
110 | SMOKE_NORMAL("smoke"),
111 | /**
112 | * @see #LARGE_SMOKE
113 | */
114 | SMOKE_LARGE(LARGE_SMOKE.getName()),
115 | SPELL("spell"),
116 | /**
117 | * @see #INSTANT_SPELL
118 | */
119 | SPELL_INSTANT(INSTANT_SPELL.getName()),
120 | /**
121 | * - Colored
122 | *
123 | * @see #MOB_SPELL
124 | */
125 | SPELL_MOB(MOB_SPELL.getName(), true),
126 | /**
127 | * @see #MOB_SPELL_AMBIENT
128 | */
129 | SPELL_MOB_AMBIENT(MOB_SPELL_AMBIENT.getName()),
130 | /**
131 | * @see #WITCH_MAGIC
132 | */
133 | SPELL_WITCH(WITCH_MAGIC.getName()),
134 | DRIP_WATER("dripWater"),
135 | DRIP_LAVA("dripLava"),
136 | /**
137 | * @see #ANGRY_VILLAGER
138 | */
139 | VILLAGER_ANGRY(ANGRY_VILLAGER.getName()),
140 | /**
141 | * @see #HAPPY_VILLAGER
142 | */
143 | VILLAGER_HAPPY(HAPPY_VILLAGER.getName()),
144 | TOWN_AURA("townaura"),
145 | /**
146 | * - Colored (Notes can be colored, but they're not fully implemented yet)
147 | */
148 | NOTE("note", true),
149 | PORTAL("portal"),
150 | ENCHANTMENT_TABLE("enchantmenttable"),
151 | FLAME("flame"),
152 | LAVA("lava"),
153 | FOOTSTEP("footstep"),
154 | CLOUD("cloud"),
155 | REDSTONE("reddust", true),
156 | SNOWBALL("snowballpoof"),
157 | SNOW_SHOVEL("snowshovel"),
158 | SLIME("slime"),
159 | HEART("heart"),
160 | /**
161 | * 1.8 only!
162 | */
163 | BARRIER("barrier"),
164 | /**
165 | * 1.8 only!
166 | */
167 | ITEM_CRACK("iconcrack_"),
168 | /**
169 | * 1.8 only!
170 | */
171 | BLOCK_CRACK("blockcrack_"),
172 | /**
173 | * 1.8 only!
174 | */
175 | BLOCK_DUST("blockdust_"),
176 | /**
177 | * 1.8 only!
178 | */
179 | WATER_DROP("droplet"),
180 | /**
181 | * 1.8 only!
182 | */
183 | ITEM_TAKE("take"),
184 | /**
185 | * 1.8 only!
186 | */
187 | MOB_APPEARANCE("mobappearance");
188 |
189 | private String particleName;
190 | private String enumValue;
191 | private boolean hasColor;
192 |
193 | ParticleEffect(String particleName, String enumValue, boolean hasColor) {
194 | this.particleName = particleName;
195 | this.enumValue = enumValue;
196 | this.hasColor = hasColor;
197 | }
198 |
199 | ParticleEffect(String particleName, String enumValue) {
200 | this(particleName, enumValue, false);
201 | }
202 |
203 | ParticleEffect(String particleName) {
204 | this(particleName, null);
205 | }
206 |
207 | ParticleEffect(String particleName, boolean hasColor) {
208 | this(particleName, null, hasColor);
209 | }
210 |
211 | public String getName() {
212 | return this.particleName;
213 | }
214 |
215 | public boolean hasColor() {
216 | return hasColor;
217 | }
218 |
219 | private static Class> nmsPacketPlayOutParticle = ReflectionUtilities.getNMSClass("PacketPlayOutWorldParticles");
220 | private static Class> nmsEnumParticle;
221 | private static int particleRange = 25;
222 |
223 | @Deprecated
224 | public static void setRange(int range) {
225 | if (range < 0) { throw new IllegalArgumentException("Range must be positive!"); }
226 | particleRange = range;
227 | }
228 |
229 | @Deprecated
230 | public static int getRange() {
231 | return particleRange;
232 | }
233 |
234 | @Deprecated
235 | private void sendToPlayer(Player player, Location location, float offsetX, float offsetY, float offsetZ, float speed, int count, int... extra) throws Exception {
236 | sendToPlayer(player, location, offsetX, offsetY, offsetZ, speed, count, false, extra);
237 | }
238 |
239 | private void sendToPlayer(Player player, Location location, float offsetX, float offsetY, float offsetZ, float speed, int count, boolean force, int... extra) throws Exception {
240 | if (!force && !isPlayerInRange(player, location)) { return; }
241 | if (ReflectionUtilities.getVersion().contains("v1_8")) {
242 | try {
243 | if (nmsEnumParticle == null) {
244 | nmsEnumParticle = ReflectionUtilities.getNMSClass("EnumParticle");
245 | }
246 | if (this == BLOCK_CRACK) {
247 | int id = 0;
248 | int data = 0;
249 | if (extra.length > 0) {
250 | id = extra[0];
251 | }
252 | if (extra.length > 1) {
253 | data = extra[1];
254 | }
255 | extra = new int[] {
256 | id,
257 | id | data << 12 };
258 | }
259 | Object packet = nmsPacketPlayOutParticle.getConstructor(new Class[] {
260 | nmsEnumParticle,
261 | boolean.class,
262 | float.class,
263 | float.class,
264 | float.class,
265 | float.class,
266 | float.class,
267 | float.class,
268 | float.class,
269 | int.class,
270 | int[].class }).newInstance(getEnum(nmsEnumParticle.getName() + "." + (this.enumValue != null ? this.enumValue : this.name().toUpperCase())), true, (float) location.getX(), (float) location.getY(), (float) location.getZ(), offsetX, offsetY, offsetZ, speed, count, extra);
271 | Object handle = ReflectionUtilities.getHandle(player);
272 | Object connection = ReflectionUtilities.getField(handle.getClass(), "playerConnection").get(handle);
273 | ReflectionUtilities.getMethod(connection.getClass(), "sendPacket", new Class[0]).invoke(connection, new Object[] { packet });
274 | } catch (Exception e) {
275 | // throw new IllegalArgumentException("Unable to send Particle " + name() + ". (Version 1.8): " + e.getMessage());
276 | throw e;
277 | }
278 | } else {
279 | try {
280 | if (this.particleName == null) {
281 | this.particleName = this.name().toLowerCase();
282 | }
283 | String name = this.particleName;
284 | if (this == BLOCK_CRACK || this == ITEM_CRACK || this == BLOCK_DUST) {
285 | int id = 0;
286 | int data = 0;
287 | if (extra.length > 0) {
288 | id = extra[0];
289 | }
290 | if (extra.length > 1) {
291 | data = extra[1];
292 | }
293 | name += id + "_" + data;
294 | }
295 | Object packet = nmsPacketPlayOutParticle.getConstructor(new Class[] {
296 | String.class,
297 | float.class,
298 | float.class,
299 | float.class,
300 | float.class,
301 | float.class,
302 | float.class,
303 | float.class,
304 | int.class }).newInstance(name, (float) location.getX(), (float) location.getY(), (float) location.getZ(), offsetX, offsetY, offsetZ, speed, count);
305 | Object handle = ReflectionUtilities.getHandle(player);
306 | Object connection = ReflectionUtilities.getField(handle.getClass(), "playerConnection").get(handle);
307 | ReflectionUtilities.getMethod(connection.getClass(), "sendPacket", new Class[0]).invoke(connection, new Object[] { packet });
308 | } catch (Exception e) {
309 | // throw new IllegalArgumentException("Unable to send Particle " + name() + ". (Server Version: 1.7) " + e.getMessage());
310 | throw e;
311 | }
312 | }
313 | }
314 |
315 | public void sendToPlayer(Player player, Location location, float offsetX, float offsetY, float offsetZ, float speed, int count, boolean force) throws Exception {
316 | this.sendToPlayer(player, location, offsetX, offsetY, offsetZ, speed, count, force, new int[0]);
317 | }
318 |
319 | @Deprecated
320 | public void sendToPlayer(Player player, Location location, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
321 | this.sendToPlayer(player, location, offsetX, offsetY, offsetZ, speed, count, false);
322 | }
323 |
324 | @Deprecated
325 | public void sendToPlayers(Collection extends Player> players, Location location, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
326 | for (Player p : players) {
327 | this.sendToPlayer(p, location, offsetX, offsetY, offsetZ, speed, count);
328 | }
329 | }
330 |
331 | public void sendToPlayers(Collection extends Player> players, Location location, float offsetX, float offsetY, float offsetZ, float speed, int count, boolean force) throws Exception {
332 | for (Player p : players) {
333 | this.sendToPlayer(p, location, offsetX, offsetY, offsetZ, speed, count, force);
334 | }
335 | }
336 |
337 | @Deprecated
338 | public void sendToPlayers(Player[] players, Location location, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
339 | for (Player p : players) {
340 | this.sendToPlayer(p, location, offsetX, offsetY, offsetZ, speed, count);
341 | }
342 | }
343 |
344 | // Color methods
345 |
346 | @Deprecated
347 | public void sendColor(Player p, Location location, org.bukkit.Color color) throws Exception {
348 | if (!this.hasColor) { return; }
349 | this.sendToPlayer(p, location, this.getColor(color.getRed()), this.getColor(color.getGreen()), this.getColor(color.getBlue()), 1, 0);
350 | }
351 |
352 | public void sendColor(Player p, Location location, org.bukkit.Color color, boolean force) throws Exception {
353 | if (!this.hasColor) { return; }
354 | this.sendToPlayer(p, location, this.getColor(color.getRed()), this.getColor(color.getGreen()), this.getColor(color.getBlue()), 1, 0, force);
355 | }
356 |
357 | @Deprecated
358 | public void sendColor(Player p, Location location, java.awt.Color color) throws Exception {
359 | if (!this.hasColor) { return; }
360 | this.sendToPlayer(p, location, this.getColor(color.getRed()), this.getColor(color.getGreen()), this.getColor(color.getBlue()), 1, 0);
361 | }
362 |
363 | public void sendColor(Player p, Location location, java.awt.Color color, boolean force) throws Exception {
364 | if (!this.hasColor) { return; }
365 | this.sendToPlayer(p, location, this.getColor(color.getRed()), this.getColor(color.getGreen()), this.getColor(color.getBlue()), 1, 0, force);
366 | }
367 |
368 | @Deprecated
369 | public void sendColor(Collection extends Player> players, Location location, java.awt.Color color) throws Exception {
370 | if (!this.hasColor) { return; }
371 | for (Player p : players) {
372 | this.sendColor(p, location, color);
373 | }
374 | }
375 |
376 | public void sendColor(Collection extends Player> players, Location location, java.awt.Color color, boolean force) throws Exception {
377 | if (!this.hasColor) { return; }
378 | for (Player p : players) {
379 | this.sendColor(p, location, color, force);
380 | }
381 | }
382 |
383 | public void sendColor(Collection extends Player> players, Location location, org.bukkit.Color color) throws Exception {
384 | if (!this.hasColor) { return; }
385 | for (Player p : players) {
386 | this.sendColor(p, location, color);
387 | }
388 | }
389 |
390 | @Deprecated
391 | public void sendColor(Collection extends Player> players, Location location, org.bukkit.Color color, boolean force) throws Exception {
392 | if (!this.hasColor) { return; }
393 | for (Player p : players) {
394 | this.sendColor(p, location, color, force);
395 | }
396 | }
397 |
398 | @Deprecated
399 | public void sendColor(Player[] players, Location location, org.bukkit.Color color) throws Exception {
400 | if (!this.hasColor) { return; }
401 | for (Player p : players) {
402 | this.sendColor(p, location, color);
403 | }
404 | }
405 |
406 | @Deprecated
407 | public void sendColor(Player[] players, Location location, java.awt.Color color) throws Exception {
408 | if (!this.hasColor) { return; }
409 | for (Player p : players) {
410 | this.sendColor(p, location, color);
411 | }
412 | }
413 |
414 | protected float getColor(float value) {
415 | if (value <= 0) {
416 | value = -1;
417 | }
418 | return value / 255;
419 | }
420 |
421 | // BLOCK_CRACK
422 |
423 | @Deprecated
424 | public void sendBlockCrack(Player player, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
425 | if (this != BLOCK_CRACK) { throw new IllegalArgumentException("This method is only available for BLOCK_CRACK!"); }
426 | this.sendToPlayer(player, location, offsetX, offsetY, offsetZ, speed, count, id, data);
427 | }
428 |
429 | public void sendBlockCrack(Player player, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count, boolean force) throws Exception {
430 | if (this != BLOCK_CRACK) { throw new IllegalArgumentException("This method is only available for BLOCK_CRACK!"); }
431 | this.sendToPlayer(player, location, offsetX, offsetY, offsetZ, speed, count, force, id, data);
432 | }
433 |
434 | @Deprecated
435 | public void sendBlockCrack(Collection extends Player> players, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
436 | if (this != BLOCK_CRACK) { throw new IllegalArgumentException("This method is only available for BLOCK_CRACK!"); }
437 | for (Player p : players) {
438 | this.sendBlockCrack(p, location, id, data, offsetX, offsetY, offsetZ, speed, count);
439 | }
440 | }
441 |
442 | public void sendBlockCrack(Collection extends Player> players, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count, boolean force) throws Exception {
443 | if (this != BLOCK_CRACK) { throw new IllegalArgumentException("This method is only available for BLOCK_CRACK!"); }
444 | for (Player p : players) {
445 | this.sendBlockCrack(p, location, id, data, offsetX, offsetY, offsetZ, speed, count, force);
446 | }
447 | }
448 |
449 | @Deprecated
450 | public void sendBlockCrack(Player[] players, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
451 | if (this != BLOCK_CRACK) { throw new IllegalArgumentException("This method is only available for BLOCK_CRACK!"); }
452 | for (Player p : players) {
453 | this.sendBlockCrack(p, location, id, data, offsetX, offsetY, offsetZ, speed, count);
454 | }
455 | }
456 |
457 | // ITEM_CRACK
458 |
459 | @Deprecated
460 | public void sendItemCrack(Player player, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
461 | if (this != ITEM_CRACK) { throw new IllegalArgumentException("This method is only available for ITEM_CRACK!"); }
462 | this.sendToPlayer(player, location, offsetX, offsetY, offsetZ, speed, count, id, data);
463 | }
464 |
465 | public void sendItemCrack(Player player, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count, boolean force) throws Exception {
466 | if (this != ITEM_CRACK) { throw new IllegalArgumentException("This method is only available for ITEM_CRACK!"); }
467 | this.sendToPlayer(player, location, offsetX, offsetY, offsetZ, speed, count, force, id, data);
468 | }
469 |
470 | @Deprecated
471 | public void sendItemCrack(Collection extends Player> players, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
472 | if (this != ITEM_CRACK) { throw new IllegalArgumentException("This method is only available for ITEM_CRACK!"); }
473 | for (Player p : players) {
474 | this.sendItemCrack(p, location, id, data, offsetX, offsetY, offsetZ, speed, count);
475 | }
476 | }
477 |
478 | public void sendItemCrack(Collection extends Player> players, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count, boolean force) throws Exception {
479 | if (this != ITEM_CRACK) { throw new IllegalArgumentException("This method is only available for ITEM_CRACK!"); }
480 | for (Player p : players) {
481 | this.sendItemCrack(p, location, id, data, offsetX, offsetY, offsetZ, speed, count, force);
482 | }
483 | }
484 |
485 | @Deprecated
486 | public void sendItemCrack(Player[] players, Location location, int id, byte data, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
487 | if (this != ITEM_CRACK) { throw new IllegalArgumentException("This method is only available for ITEM_CRACK!"); }
488 | for (Player p : players) {
489 | this.sendItemCrack(p, location, id, data, offsetX, offsetY, offsetZ, speed, count);
490 | }
491 | }
492 |
493 | // BLOCK_DUST
494 |
495 | @Deprecated
496 | public void sendBlockDust(Player p, Location location, int id, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
497 | if (this != BLOCK_DUST) { throw new IllegalArgumentException("This method is only available for BLOCK_DUST!"); }
498 | this.sendToPlayer(p, location, offsetX, offsetY, offsetZ, speed, count, id);
499 | }
500 |
501 | public void sendBlockDust(Player p, Location location, int id, float offsetX, float offsetY, float offsetZ, float speed, int count, boolean force) throws Exception {
502 | if (this != BLOCK_DUST) { throw new IllegalArgumentException("This method is only available for BLOCK_DUST!"); }
503 | this.sendToPlayer(p, location, offsetX, offsetY, offsetZ, speed, count, force, id);
504 | }
505 |
506 | @Deprecated
507 | public void sendBlockDust(Collection extends Player> players, Location location, int id, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
508 | if (this != BLOCK_DUST) { throw new IllegalArgumentException("This method is only available for BLOCK_DUST!"); }
509 | for (Player p : players) {
510 | this.sendBlockDust(p, location, id, offsetX, offsetY, offsetZ, speed, count);
511 | }
512 | }
513 |
514 | public void sendBlockDust(Collection extends Player> players, Location location, int id, float offsetX, float offsetY, float offsetZ, float speed, int count, boolean force) throws Exception {
515 | if (this != BLOCK_DUST) { throw new IllegalArgumentException("This method is only available for BLOCK_DUST!"); }
516 | for (Player p : players) {
517 | this.sendBlockDust(p, location, id, offsetX, offsetY, offsetZ, speed, count, force);
518 | }
519 | }
520 |
521 | @Deprecated
522 | public void sendBlockDust(Player[] players, Location location, int id, float offsetX, float offsetY, float offsetZ, float speed, int count) throws Exception {
523 | if (this != BLOCK_DUST) { throw new IllegalArgumentException("This method is only available for BLOCK_DUST!"); }
524 | for (Player p : players) {
525 | this.sendBlockDust(p, location, id, offsetX, offsetY, offsetZ, speed, count);
526 | }
527 | }
528 |
529 | // Reflection
530 |
531 | private static Class> nmsPlayerConnection;
532 | private static Class> nmsEntityPlayer;
533 | private static Class> ioNettyChannel;
534 | private static Method nmsNetworkGetVersion;
535 |
536 | private static Field nmsFieldPlayerConnection;
537 | private static Field nmsFieldNetworkManager;
538 | private static Field nmsFieldNetworkManagerI;
539 | private static Field nmsFieldNetworkManagerM;
540 |
541 | protected static int getVersion(Player p) {
542 | try {
543 | final Object handle = ReflectionUtilities.getHandle(p);
544 | final Object connection = nmsFieldPlayerConnection.get(handle);
545 | final Object network = nmsFieldNetworkManager.get(connection);
546 | final Object channel;
547 | if (ReflectionUtilities.getVersion().contains("1_7")) {
548 | channel = nmsFieldNetworkManagerM.get(network);
549 | } else {
550 | channel = nmsFieldNetworkManagerI.get(network);
551 | }
552 | final Object version = ReflectionUtilities.getVersion().contains("1_7") ? nmsNetworkGetVersion.invoke(network, channel) : 47;
553 | return (int) version;
554 | } catch (Exception e) {
555 | e.printStackTrace();
556 | }
557 | return 0;
558 | }
559 |
560 | static {
561 | String ver = ReflectionUtilities.getVersion();
562 | try {
563 | nmsPlayerConnection = ReflectionUtilities.getNMSClass("PlayerConnection");
564 | nmsEntityPlayer = ReflectionUtilities.getNMSClass("EntityPlayer");
565 | ioNettyChannel = ver.contains("1_7") ? Class.forName("net.minecraft.util.io.netty.channel.Channel") : Class.forName("io.netty.channel.Channel");
566 |
567 | nmsFieldPlayerConnection = ReflectionUtilities.getField(nmsEntityPlayer, "playerConnection");
568 | nmsFieldNetworkManager = ReflectionUtilities.getField(nmsPlayerConnection, "networkManager");
569 | nmsFieldNetworkManagerI = ReflectionUtilities.getField(nmsFieldNetworkManager.getType(), "i");
570 | nmsFieldNetworkManagerM = ReflectionUtilities.getField(nmsFieldNetworkManager.getType(), "m");
571 |
572 | nmsNetworkGetVersion = ReflectionUtilities.getMethod(nmsFieldNetworkManager.getType(), "getVersion", ioNettyChannel);
573 |
574 | } catch (Exception e) {
575 | System.err.println("[ParticleLIB] Error while loading: " + e.getMessage());
576 | e.printStackTrace(System.err);
577 | Bukkit.getPluginManager().disablePlugin(Bukkit.getPluginManager().getPlugin("ParticleLIB"));
578 | }
579 | }
580 |
581 | @SuppressWarnings({
582 | "unchecked",
583 | "rawtypes" })
584 | private static Enum> getEnum(String enumFullName) {
585 | String[] x = enumFullName.split("\\.(?=[^\\.]+$)");
586 | if (x.length == 2) {
587 | String enumClassName = x[0];
588 | String enumName = x[1];
589 | try {
590 | Class cl = (Class) Class.forName(enumClassName);
591 | return Enum.valueOf(cl, enumName);
592 | } catch (ClassNotFoundException e) {
593 | e.printStackTrace();
594 | }
595 | }
596 | return null;
597 | }
598 |
599 | public static boolean isPlayerInRange(Player p, Location center) {
600 | double distance = 0;
601 | if (!p.getLocation().getWorld().equals(center.getWorld())) { return false; }
602 | if ((distance = center.distanceSquared(p.getLocation())) > Double.MAX_VALUE) { return false; }
603 | return distance < particleRange * particleRange;
604 | }
605 |
606 | public static class ReflectionUtilities {
607 |
608 | public static void setValue(Object instance, String fieldName, Object value) throws Exception {
609 | Field field = instance.getClass().getDeclaredField(fieldName);
610 | field.setAccessible(true);
611 | field.set(instance, value);
612 | }
613 |
614 | public static Object getValue(Object instance, String fieldName) throws Exception {
615 | Field field = instance.getClass().getDeclaredField(fieldName);
616 | field.setAccessible(true);
617 | return field.get(instance);
618 | }
619 |
620 | public static String getVersion() {
621 | String name = Bukkit.getServer().getClass().getPackage().getName();
622 | String version = name.substring(name.lastIndexOf('.') + 1) + ".";
623 | return version;
624 | }
625 |
626 | public static Class> getNMSClass(String className) {
627 | String fullName = "net.minecraft.server." + getVersion() + className;
628 | Class> clazz = null;
629 | try {
630 | clazz = Class.forName(fullName);
631 | } catch (Exception e) {
632 | e.printStackTrace();
633 | }
634 | return clazz;
635 | }
636 |
637 | public static Class> getOBCClass(String className) {
638 | String fullName = "org.bukkit.craftbukkit." + getVersion() + className;
639 | Class> clazz = null;
640 | try {
641 | clazz = Class.forName(fullName);
642 | } catch (Exception e) {
643 | e.printStackTrace();
644 | }
645 | return clazz;
646 | }
647 |
648 | public static Object getHandle(Object obj) {
649 | try {
650 | return getMethod(obj.getClass(), "getHandle", new Class[0]).invoke(obj, new Object[0]);
651 | } catch (Exception e) {
652 | e.printStackTrace();
653 | }
654 | return null;
655 | }
656 |
657 | public static Field getField(Class> clazz, String name) {
658 | try {
659 | Field field = clazz.getDeclaredField(name);
660 | field.setAccessible(true);
661 | return field;
662 | } catch (Exception e) {
663 | e.printStackTrace();
664 | }
665 | return null;
666 | }
667 |
668 | public static Method getMethod(Class> clazz, String name, Class>... args) {
669 | for (Method m : clazz.getMethods()) {
670 | if (m.getName().equals(name) && (args.length == 0 || ClassListEqual(args, m.getParameterTypes()))) {
671 | m.setAccessible(true);
672 | return m;
673 | }
674 | }
675 | return null;
676 | }
677 |
678 | public static boolean ClassListEqual(Class>[] l1, Class>[] l2) {
679 | boolean equal = true;
680 | if (l1.length != l2.length) { return false; }
681 | for (int i = 0; i < l1.length; i++) {
682 | if (l1[i] != l2[i]) {
683 | equal = false;
684 | break;
685 | }
686 | }
687 | return equal;
688 | }
689 | }
690 | }
691 |
--------------------------------------------------------------------------------
/src/main/java/org/inventivetalent/particle/ParticleEffect.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 inventivetalent. All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without modification, are
5 | * permitted provided that the following conditions are met:
6 | *
7 | * 1. Redistributions of source code must retain the above copyright notice, this list of
8 | * conditions and the following disclaimer.
9 | *
10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 | * of conditions and the following disclaimer in the documentation and/or other materials
12 | * provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 | *
24 | * The views and conclusions contained in the software and documentation are those of the
25 | * authors and contributors and should not be interpreted as representing official policies,
26 | * either expressed or implied, of anybody else.
27 | */
28 |
29 | package org.inventivetalent.particle;
30 |
31 | import org.bukkit.Color;
32 | import org.bukkit.Location;
33 | import org.bukkit.entity.Player;
34 | import org.bukkit.inventory.ItemStack;
35 | import org.inventivetalent.reflection.minecraft.Minecraft;
36 | import org.inventivetalent.reflection.resolver.ConstructorResolver;
37 | import org.inventivetalent.reflection.resolver.FieldResolver;
38 | import org.inventivetalent.reflection.resolver.MethodResolver;
39 | import org.inventivetalent.reflection.resolver.minecraft.NMSClassResolver;
40 |
41 | import java.lang.reflect.InvocationTargetException;
42 | import java.util.ArrayList;
43 | import java.util.Collection;
44 | import java.util.Iterator;
45 |
46 | import static org.inventivetalent.reflection.minecraft.Minecraft.Version.*;
47 |
48 | public enum ParticleEffect {
49 |
50 | EXPLOSION_NORMAL("explode"),
51 | EXPLOSION_LARGE("largeexplode"),
52 | EXPLOSION_HUGE("hugeexplosion"),
53 | FIREWORKS_SPARK("fireworksSpark"),
54 | WATER_BUBBLE("bubble"),
55 | WATER_SPLASH("splash"),
56 | WATER_WAKE("wake"),
57 | SUSPENDED("suspended"),
58 | SUSPENDED_DEPTH("depthsuspend"),
59 | CRIT("crit"),
60 | CRIT_MAGIC("magicCrit"),
61 | SMOKE_NORMAL("smoke"),
62 | SMOKE_LARGE("largesmoke"),
63 | SPELL("spell"),
64 | SPELL_INSTANT("instantSpell"),
65 | SPELL_MOB("mobSpell", v1_7_R1, Feature.COLOR),
66 | SPELL_MOB_AMBIENT("mobSpellAmbient"),
67 | SPELL_WITCH("witchMagic"),
68 | DRIP_WATER("dripWater"),
69 | DRIP_LAVA("dripLava"),
70 | VILLAGER_ANGRY("angryVillager"),
71 | VILLAGER_HAPPY("happyVillager"),
72 | TOWN_AURA("townaura"),
73 | NOTE("note", v1_7_R1, Feature.COLOR),
74 | PORTAL("portal"),
75 | ENCHANTMENT_TABLE("enchantmenttable"),
76 | FLAME("flame"),
77 | LAVA("lava"),
78 | FOOTSTEP("footstep"),
79 | CLOUD("cloud"),
80 | REDSTONE("reddust", v1_7_R1, Feature.COLOR),
81 | SNOWBALL("snowballpoof"),
82 | SNOW_SHOVEL("snowshovel"),
83 | SLIME("slime"),
84 | HEART("heart"),
85 | BARRIER("barrier", v1_8_R1),
86 | ITEM_CRACK("iconcrack_", v1_7_R1, Feature.DATA) {
87 | //Unsupported methods
88 | @Override
89 | public void send(Collection extends Player> receivers, Location location, double offsetX, double offsetY, double offsetZ, double speed, int count) {
90 | throw new ParticleException("Cannot use default send() for ITEM_CRACK");
91 | }
92 |
93 | @Override
94 | public void send(Collection extends Player> receivers, Location location, double offsetX, double offsetY, double offsetZ, double speed, int count, double range) {
95 | throw new ParticleException("Cannot use default send() for ITEM_CRACK");
96 | }
97 |
98 | @Override
99 | public void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, double range) {
100 | throw new ParticleException("Cannot use default send() for ITEM_CRACK");
101 | }
102 |
103 | @Override
104 | public void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count) {
105 | throw new ParticleException("Cannot use default send() for ITEM_CRACK");
106 | }
107 | },
108 | BLOCK_CRACK("blockcrack_", v1_7_R1, Feature.DATA) {
109 | //Unsupported methods
110 | @Override
111 | public void send(Collection extends Player> receivers, Location location, double offsetX, double offsetY, double offsetZ, double speed, int count) {
112 | throw new ParticleException("Cannot use default send() for BLOCK_CRACK");
113 | }
114 |
115 | @Override
116 | public void send(Collection extends Player> receivers, Location location, double offsetX, double offsetY, double offsetZ, double speed, int count, double range) {
117 | throw new ParticleException("Cannot use default send() for BLOCK_CRACK");
118 | }
119 |
120 | @Override
121 | public void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, double range) {
122 | throw new ParticleException("Cannot use default send() for BLOCK_CRACK");
123 | }
124 |
125 | @Override
126 | public void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count) {
127 | throw new ParticleException("Cannot use default send() for BLOCK_CRACK");
128 | }
129 | },
130 | BLOCK_DUST("blockdust_", v1_7_R1, Feature.DATA) {
131 | @Override
132 | public void sendData(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, int itemId, byte data) {
133 | data = -1;
134 | super.sendData(receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count, itemId, data);
135 | }
136 |
137 | //Unsupported methods
138 | @Override
139 | public void send(Collection extends Player> receivers, Location location, double offsetX, double offsetY, double offsetZ, double speed, int count) {
140 | throw new ParticleException("Cannot use default send() for BLOCK_DUST");
141 | }
142 |
143 | @Override
144 | public void send(Collection extends Player> receivers, Location location, double offsetX, double offsetY, double offsetZ, double speed, int count, double range) {
145 | throw new ParticleException("Cannot use default send() for BLOCK_DUST");
146 | }
147 |
148 | @Override
149 | public void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, double range) {
150 | throw new ParticleException("Cannot use default send() for BLOCK_DUST");
151 | }
152 |
153 | @Override
154 | public void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count) {
155 | throw new ParticleException("Cannot use default send() for BLOCK_DUST");
156 | }
157 | },
158 | WATER_DROP("droplet", v1_8_R1),
159 | ITEM_TAKE("take", v1_8_R1),
160 | MOB_APPEARANCE("mobappearance", v1_8_R1),
161 | DRAGON_BREATH("dragonbreath", v1_9_R1),
162 | END_ROD("endRod", v1_9_R1),
163 | DAMAGE_INDICATOR("damageIndicator", v1_9_R1),
164 | SWEEP_ATTACK("sweepAttack", v1_9_R1),
165 | FALLING_DUST("fallingDust", v1_10_R1),
166 | SPIT("spit", v1_11_R1),
167 | TOTEM("totem", v1_11_R1);
168 |
169 | private String name;
170 | private Minecraft.Version minVersion;
171 | private Feature feature;
172 | protected Particle particle;
173 |
174 | ParticleEffect(String name, Minecraft.Version minVersion, Feature feature) {
175 | this.name = name;
176 | this.minVersion = minVersion;
177 | this.feature = feature;
178 | if (feature != null) {
179 | this.particle = feature.particle(this);
180 | } else {
181 | this.particle = new Particle(this);
182 | }
183 | }
184 |
185 | ParticleEffect(String name, Minecraft.Version minVersion) {
186 | this(name, minVersion, null);
187 | }
188 |
189 | ParticleEffect(String name) {
190 | this(name, v1_7_R1);
191 | }
192 |
193 | public String getName() {
194 | return name;
195 | }
196 |
197 | /**
198 | * @return the minimum {@link org.inventivetalent.reflection.minecraft.Minecraft.Version} required for this particle
199 | */
200 | public Minecraft.Version getMinVersion() {
201 | return minVersion;
202 | }
203 |
204 | /**
205 | * @return true
if this particle is compatible with the server version
206 | */
207 | public boolean isCompatible() {
208 | return Minecraft.VERSION.newerThan(getMinVersion());
209 | }
210 |
211 | /**
212 | * Check if this particle has special {@link org.inventivetalent.particle.ParticleEffect.Feature}s - Particles with features cannot use the default send() methods - Particles without features cannot use special sendColor or sendData methods
213 | *
214 | * @param feature {@link org.inventivetalent.particle.ParticleEffect.Feature} to check
215 | * @return true
if this particle has the feature
216 | * @see #hasNoFeatures()
217 | */
218 | public boolean hasFeature(Feature feature) {
219 | return this.feature == feature;
220 | }
221 |
222 | /**
223 | * Check if this particle has no {@link org.inventivetalent.particle.ParticleEffect.Feature}s - Particles without features cannot use special sendColor or sendData methods - Particles with features cannot use the default send() methods
224 | *
225 | * @return true
if this particle has no special features
226 | * @see #hasFeature(Feature)
227 | */
228 | public boolean hasNoFeatures() {
229 | return this.feature == null;
230 | }
231 |
232 | //*** Public send methods
233 |
234 | //General
235 |
236 | /**
237 | * Send this particle
238 | *
239 | * @param receivers Collection of receivers
240 | * @param x X-Location
241 | * @param y Y-Location
242 | * @param z Z-Location
243 | * @param offsetX X-Offset
244 | * @param offsetY Y-Offset
245 | * @param offsetZ Z-Offset
246 | * @param speed Particle speed
247 | * @param count Particle count
248 | * @param range Maximum visibility range
249 | */
250 | public void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, double range) {
251 | double squareRange = range * range;
252 | Collection inRange = new ArrayList<>();
253 | for (Player receiver : receivers) {
254 | if (receiver.getLocation().distanceSquared(new Location(receiver.getWorld(), x, y, z)) <= squareRange) { inRange.add(receiver); }
255 | }
256 | this.send(inRange, x, y, z, offsetX, offsetY, offsetZ, speed, count);
257 | }
258 |
259 | /**
260 | * Send this particle
261 | *
262 | * @param receivers Collection of receivers
263 | * @param location {@link Location}
264 | * @param offsetX X-Offset
265 | * @param offsetY Y-Offset
266 | * @param offsetZ Z-Offset
267 | * @param speed Particle speed
268 | * @param count Particle count
269 | * @param range Maximum visibility range
270 | */
271 | public void send(Collection extends Player> receivers, Location location, double offsetX, double offsetY, double offsetZ, double speed, int count, double range) {
272 | receivers = new ArrayList<>(receivers);
273 | for (Iterator extends Player> iterator = receivers.iterator(); iterator.hasNext(); ) {
274 | if (!iterator.next().getWorld().getName().equals(location.getWorld().getName())) { iterator.remove(); }
275 | }
276 | send(receivers, location.getX(), location.getY(), location.getZ(), offsetX, offsetY, offsetZ, speed, count, range);
277 | }
278 |
279 | /**
280 | * Send this particle
281 | *
282 | * @param receivers Collection of receivers
283 | * @param x X-Location
284 | * @param y Y-Location
285 | * @param z Z-Location
286 | * @param offsetX X-Offset
287 | * @param offsetY Y-Offset
288 | * @param offsetZ Z-Offset
289 | * @param speed Particle speed
290 | * @param count Particle count
291 | */
292 | public void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count) {
293 | this.particle.send(receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count);
294 | }
295 |
296 | /**
297 | * Send this particle
298 | *
299 | * @param receivers Collection of receivers
300 | * @param location {@link Location}
301 | * @param offsetX X-Offset
302 | * @param offsetY Y-Offset
303 | * @param offsetZ Z-Offset
304 | * @param speed Particle speed
305 | * @param count Particle count
306 | */
307 | public void send(Collection extends Player> receivers, Location location, double offsetX, double offsetY, double offsetZ, double speed, int count) {
308 | receivers = new ArrayList<>(receivers);
309 | for (Iterator extends Player> iterator = receivers.iterator(); iterator.hasNext(); ) {
310 | if (!iterator.next().getWorld().getName().equals(location.getWorld().getName())) { iterator.remove(); }
311 | }
312 | this.particle.send(receivers, location.getX(), location.getY(), location.getZ(), offsetX, offsetY, offsetZ, speed, count);
313 | }
314 |
315 | //Color
316 |
317 | /**
318 | * Send this particle with a color
319 | *
320 | * @param receivers Collection of receivers
321 | * @param x X-Location
322 | * @param y Y-Location
323 | * @param z Z-Location
324 | * @param color {@link org.bukkit.Color} of the particle
325 | * @throws ParticleException if this particle cannot have a color
326 | */
327 | public void sendColor(Collection extends Player> receivers, double x, double y, double z, org.bukkit.Color color) {
328 | if (!hasFeature(Feature.COLOR)) { throw new ParticleException("This particle cannot be colored"); }
329 | ((ColoredParticle) this.particle).send(receivers, x, y, z, color);
330 | }
331 |
332 | /**
333 | * Send this particle with a color
334 | *
335 | * @param receivers Collection of receivers
336 | * @param x X-Location
337 | * @param y Y-Location
338 | * @param z Z-Location
339 | * @param color {@link java.awt.Color} of the particle
340 | * @throws ParticleException if this particle cannot have a color
341 | */
342 | public void sendColor(Collection extends Player> receivers, double x, double y, double z, java.awt.Color color) {
343 | if (!hasFeature(Feature.COLOR)) { throw new ParticleException("This particle cannot be colored"); }
344 | ((ColoredParticle) this.particle).send(receivers, x, y, z, color);
345 | }
346 |
347 | public void sendColor(Collection extends Player> receivers, Location location, Color color) {
348 | receivers = new ArrayList<>(receivers);
349 | for (Iterator extends Player> iterator = receivers.iterator(); iterator.hasNext(); ) {
350 | if (!iterator.next().getWorld().getName().equals(location.getWorld().getName())) { iterator.remove(); }
351 | }
352 | sendColor(receivers, location.getX(), location.getY(), location.getZ(), color);
353 | }
354 |
355 | public void sendColor(Collection extends Player> receivers, Location location, java.awt.Color color) {
356 | receivers = new ArrayList<>(receivers);
357 | for (Iterator extends Player> iterator = receivers.iterator(); iterator.hasNext(); ) {
358 | if (!iterator.next().getWorld().getName().equals(location.getWorld().getName())) { iterator.remove(); }
359 | }
360 | sendColor(receivers, location.getX(), location.getY(), location.getZ(), color);
361 | }
362 |
363 | //Data
364 |
365 | /**
366 | * Send this particle with block or item data
367 | *
368 | * @param receivers Collection of receivers
369 | * @param x X-Location
370 | * @param y Y-Location
371 | * @param z Z-Location
372 | * @param offsetX X-Offset
373 | * @param offsetY Y-Offset
374 | * @param offsetZ Z-Offset
375 | * @param speed Particle speed
376 | * @param count Particle count
377 | * @param itemId ID of the item/block
378 | * @param data Data of the item/block
379 | * @throws ParticleException if this particle cannot have block or item data
380 | */
381 | public void sendData(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, int itemId, byte data) {
382 | if (!hasFeature(Feature.DATA)) { throw new ParticleException("This particle cannot have block/item data"); }
383 | ((DataParticle) this.particle).send(receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count, itemId, data);
384 | }
385 |
386 | /**
387 | * Send this particle with block or item data
388 | *
389 | * @param receivers Collection of receivers
390 | * @param x X-Location
391 | * @param y Y-Location
392 | * @param z Z-Location
393 | * @param offsetX X-Offset
394 | * @param offsetY Y-Offset
395 | * @param offsetZ Z-Offset
396 | * @param speed Particle speed
397 | * @param count Particle count
398 | * @param itemStack {@link ItemStack} containing the ID&data of the item/block
399 | * @throws ParticleException if this particle cannot have block or item data
400 | */
401 | public void sendData(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, ItemStack itemStack) {
402 | sendData(receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count, itemStack.getTypeId(), itemStack.getData().getData());
403 | }
404 |
405 | public enum Feature {
406 | /**
407 | * The particle can be colore
408 | */
409 | COLOR {
410 | @Override
411 | Particle particle(ParticleEffect effect) {
412 | return new ColoredParticle(effect);
413 | }
414 | },
415 | /**
416 | * The particle can have item or block data
417 | */
418 | DATA {
419 | @Override
420 | Particle particle(ParticleEffect effect) {
421 | return new DataParticle(effect);
422 | }
423 | };
424 |
425 | Feature() {
426 | }
427 |
428 | public boolean applies(ParticleEffect particleEffect) {
429 | return particleEffect.hasFeature(this);
430 | }
431 |
432 | Particle particle(ParticleEffect effect) {
433 | return new Particle(effect);
434 | }
435 |
436 | }
437 |
438 | static class Particle {
439 | final Class> PacketParticle = Reflection.NMS_CLASS_RESOLVER.resolveSilent("PacketPlayOutWorldParticles");
440 | final Class> EnumParticle = Reflection.NMS_CLASS_RESOLVER.resolveSilent("EnumParticle");
441 | final ConstructorResolver PacketParticleConstructorResolver = new ConstructorResolver(PacketParticle);
442 |
443 | ParticleEffect effect;
444 |
445 | Particle(ParticleEffect particleEffect) {
446 | this.effect = particleEffect;
447 | }
448 |
449 | void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, int... extra) {
450 | if (!this.effect.isCompatible()) { throw new ParticleException("Particle " + this.effect + " is not compatible with the server version (" + Minecraft.VERSION + " < " + this.effect.getMinVersion() + ")"); }
451 | try {
452 | if (Minecraft.VERSION.newerThan(v1_8_R1)) {
453 | send_1_8(receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count, extra);
454 | } else {//1.7
455 | send_1_7(effect.name, receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count);
456 | }
457 | } catch (Exception e) {
458 | throw new ParticleException("Failed to send particle " + this.effect + " to " + receivers.toString(), e);
459 | }
460 | }
461 |
462 | void send_1_8(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, int... extra) throws Exception {
463 | Object packet = PacketParticleConstructorResolver.resolve(new Class[] {
464 | EnumParticle,
465 | boolean.class,
466 | float.class,
467 | float.class,
468 | float.class,
469 | float.class,
470 | float.class,
471 | float.class,
472 | float.class,
473 | int.class,
474 | int[].class }).newInstance(//
475 | getEnum(EnumParticle.getName() + "." + effect.name()),//particle enum
476 | true,//long-distance
477 | (float) x,//X
478 | (float) y,//Y
479 | (float) z,//Z
480 | (float) offsetX,//X-offset
481 | (float) offsetY,//Y-offset
482 | (float) offsetZ,//Z-offset
483 | (float) speed,//Speed
484 | count,//Count
485 | extra//Extra
486 | );
487 |
488 | for (Player receiver : receivers) {
489 | sendPacket(packet, receiver);
490 | }
491 | }
492 |
493 | void send_1_7(String name, Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count) throws Exception {
494 | Object packet = PacketParticleConstructorResolver.resolve(new Class[] {
495 | String.class,
496 | float.class,
497 | float.class,
498 | float.class,
499 | float.class,
500 | float.class,
501 | float.class,
502 | float.class,
503 | int.class }).newInstance(//
504 | name,//Particle name
505 | (float) x,//X
506 | (float) y,//Y
507 | (float) z, //Z
508 | (float) offsetX,//X
509 | (float) offsetY,//Y
510 | (float) offsetZ,//Z
511 | (float) speed,//Speed
512 | count//Count
513 | );
514 |
515 | for (Player receiver : receivers) {
516 | sendPacket(packet, receiver);
517 | }
518 | }
519 | }
520 |
521 | static class ColoredParticle extends Particle {
522 |
523 | ColoredParticle(ParticleEffect particleEffect) {
524 | super(particleEffect);
525 | }
526 |
527 | void send(Collection extends Player> receivers, double x, double y, double z, org.bukkit.Color color) {
528 | send(receivers, x, y, z, getColor(color.getRed()), getColor(color.getGreen()), getColor(color.getBlue()), 1, 0);
529 | }
530 |
531 | void send(Collection extends Player> receivers, double x, double y, double z, java.awt.Color color) {
532 | send(receivers, x, y, z, getColor(color.getRed()), getColor(color.getGreen()), getColor(color.getBlue()), 1, 0);
533 | }
534 |
535 | @Override
536 | void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, int... extra) {
537 | super.send(receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count, extra);
538 | }
539 |
540 | double getColor(double value) {
541 | if (value <= 0) {
542 | value = -1;
543 | }
544 | return value / 255;
545 | }
546 | }
547 |
548 | static class DataParticle extends Particle {
549 |
550 | DataParticle(ParticleEffect particleEffect) {
551 | super(particleEffect);
552 | }
553 |
554 | void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, int id, byte data) {
555 | try {
556 | if (Minecraft.VERSION.newerThan(v1_8_R1)) {
557 | send_1_8(receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count, new int[] {
558 | id,
559 | id | data << 12 });
560 | } else {
561 | send_1_7(effect.name + id + (data >= 0 ? "_" + data : ""), receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count);
562 | }
563 | } catch (Exception e) {
564 | throw new ParticleException("Failed to send particle " + this.effect + " to " + receivers.toString(), e);
565 | }
566 | }
567 |
568 | @Override
569 | void send(Collection extends Player> receivers, double x, double y, double z, double offsetX, double offsetY, double offsetZ, double speed, int count, int... extra) {
570 | super.send(receivers, x, y, z, offsetX, offsetY, offsetZ, speed, count, extra);
571 | }
572 | }
573 |
574 | static Enum> getEnum(String enumFullName) {
575 | String[] x = enumFullName.split("\\.(?=[^\\.]+$)");
576 | if (x.length == 2) {
577 | String enumClassName = x[0];
578 | String enumName = x[1];
579 | try {
580 | Class cl = (Class) Class.forName(enumClassName);
581 | return Enum.valueOf(cl, enumName);
582 | } catch (ClassNotFoundException e) {
583 | e.printStackTrace();
584 | }
585 | }
586 | return null;
587 | }
588 |
589 | static class Reflection {
590 |
591 | static final NMSClassResolver NMS_CLASS_RESOLVER = new NMSClassResolver();
592 | //Packets
593 | private static FieldResolver EntityPlayerFieldResolver;
594 | private static MethodResolver PlayerConnectionMethodResolver;
595 | }
596 |
597 | protected static void sendPacket(Object packet, Player p) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
598 | if (Reflection.EntityPlayerFieldResolver == null) {
599 | Reflection.EntityPlayerFieldResolver = new FieldResolver(Reflection.NMS_CLASS_RESOLVER.resolve("EntityPlayer"));
600 | }
601 | if (Reflection.PlayerConnectionMethodResolver == null) {
602 | Reflection.PlayerConnectionMethodResolver = new MethodResolver(Reflection.NMS_CLASS_RESOLVER.resolve("PlayerConnection"));
603 | }
604 |
605 | try {
606 | Object handle = Minecraft.getHandle(p);
607 | final Object connection = Reflection.EntityPlayerFieldResolver.resolve("playerConnection").get(handle);
608 | Reflection.PlayerConnectionMethodResolver.resolve("sendPacket").invoke(connection, packet);
609 | } catch (ReflectiveOperationException e) {
610 | throw new RuntimeException(e);
611 | }
612 | }
613 |
614 | }
615 |
--------------------------------------------------------------------------------
/src/main/java/org/inventivetalent/particle/ParticleException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 inventivetalent. All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without modification, are
5 | * permitted provided that the following conditions are met:
6 | *
7 | * 1. Redistributions of source code must retain the above copyright notice, this list of
8 | * conditions and the following disclaimer.
9 | *
10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 | * of conditions and the following disclaimer in the documentation and/or other materials
12 | * provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 | *
24 | * The views and conclusions contained in the software and documentation are those of the
25 | * authors and contributors and should not be interpreted as representing official policies,
26 | * either expressed or implied, of anybody else.
27 | */
28 |
29 | package org.inventivetalent.particle;
30 |
31 | public class ParticleException extends RuntimeException {
32 | public ParticleException() {
33 | }
34 |
35 | public ParticleException(String message) {
36 | super(message);
37 | }
38 |
39 | public ParticleException(String message, Throwable cause) {
40 | super(message, cause);
41 | }
42 |
43 | public ParticleException(Throwable cause) {
44 | super(cause);
45 | }
46 |
47 | public ParticleException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
48 | super(message, cause, enableSuppression, writableStackTrace);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/org/inventivetalent/particle/ParticlePlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 inventivetalent. All rights reserved.
3 | *
4 | * Redistribution and use in source and binary forms, with or without modification, are
5 | * permitted provided that the following conditions are met:
6 | *
7 | * 1. Redistributions of source code must retain the above copyright notice, this list of
8 | * conditions and the following disclaimer.
9 | *
10 | * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 | * of conditions and the following disclaimer in the documentation and/or other materials
12 | * provided with the distribution.
13 | *
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
15 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 | * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 | *
24 | * The views and conclusions contained in the software and documentation are those of the
25 | * authors and contributors and should not be interpreted as representing official policies,
26 | * either expressed or implied, of anybody else.
27 | */
28 |
29 | package org.inventivetalent.particle;
30 |
31 | import org.bukkit.event.Listener;
32 | import org.bukkit.plugin.java.JavaPlugin;
33 |
34 | public class ParticlePlugin extends JavaPlugin implements Listener {
35 |
36 | @Override
37 | public void onEnable() {
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/resources/plugin.yml:
--------------------------------------------------------------------------------
1 | name: ParticleLIB
2 | main: org.inventivetalent.particle.ParticlePlugin
3 | version: ${project.version}
4 | author: inventivetalent
--------------------------------------------------------------------------------