Commits

md_5 authored 5e5cf84f2cc
SPIGOT-2581: EntityAirChangeEvent
No tags

nms-patches/Entity.patch

Modified
1 1 --- a/net/minecraft/server/Entity.java
2 2 +++ b/net/minecraft/server/Entity.java
3 -@@ -15,8 +15,47 @@
3 +@@ -15,8 +15,48 @@
4 4 import org.apache.logging.log4j.LogManager;
5 5 import org.apache.logging.log4j.Logger;
6 6
7 7 +// CraftBukkit start
8 8 +import org.bukkit.Bukkit;
9 9 +import org.bukkit.Location;
10 10 +import org.bukkit.Server;
11 11 +import org.bukkit.TravelAgent;
12 12 +import org.bukkit.block.BlockFace;
13 13 +import org.bukkit.entity.Hanging;
14 14 +import org.bukkit.entity.LivingEntity;
15 15 +import org.bukkit.entity.Vehicle;
16 16 +import org.bukkit.event.entity.EntityCombustByEntityEvent;
17 17 +import org.bukkit.event.hanging.HangingBreakByEntityEvent;
18 18 +import org.bukkit.event.vehicle.VehicleBlockCollisionEvent;
19 19 +import org.bukkit.event.vehicle.VehicleEnterEvent;
20 20 +import org.bukkit.event.vehicle.VehicleExitEvent;
21 21 +import org.bukkit.craftbukkit.CraftWorld;
22 22 +import org.bukkit.craftbukkit.entity.CraftEntity;
23 23 +import org.bukkit.craftbukkit.entity.CraftPlayer;
24 24 +import org.bukkit.craftbukkit.event.CraftEventFactory;
25 ++import org.bukkit.event.entity.EntityAirChangeEvent;
25 26 +import org.bukkit.event.entity.EntityCombustEvent;
26 27 +import org.bukkit.event.entity.EntityPortalEvent;
27 28 +import org.bukkit.plugin.PluginManager;
28 29 +// CraftBukkit end
29 30 +
30 31 public abstract class Entity implements ICommandListener {
31 32
32 33 + // CraftBukkit start
33 34 + private static final int CURRENT_LEVEL = 2;
34 35 + static boolean isLevelAtLeast(NBTTagCompound tag, int level) {
41 42 + if (bukkitEntity == null) {
42 43 + bukkitEntity = CraftEntity.getEntity(world.getServer(), this);
43 44 + }
44 45 + return bukkitEntity;
45 46 + }
46 47 + // CraftBukikt end
47 48 +
48 49 private static final Logger a = LogManager.getLogger();
49 50 private static final AxisAlignedBB b = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
50 51 private static double c = 1.0D;
51 -@@ -99,6 +138,9 @@
52 +@@ -99,6 +139,9 @@
52 53 public boolean glowing;
53 54 private final Set<String> aH;
54 55 private boolean aI;
55 56 + public boolean valid; // CraftBukkit
56 57 + public org.bukkit.projectiles.ProjectileSource projectileSource; // CraftBukkit - For projectiles only
57 58 + public boolean forceExplosionKnockback; // CraftBukkit - SPIGOT-949
58 59
59 60 public Entity(World world) {
60 61 this.id = Entity.entityCount++;
61 -@@ -197,6 +239,33 @@
62 +@@ -197,6 +240,33 @@
62 63 }
63 64
64 65 protected void setYawPitch(float f, float f1) {
65 66 + // CraftBukkit start - yaw was sometimes set to NaN, so we need to set it back to 0
66 67 + if (Float.isNaN(f)) {
67 68 + f = 0;
68 69 + }
69 70 +
70 71 + if (f == Float.POSITIVE_INFINITY || f == Float.NEGATIVE_INFINITY) {
71 72 + if (this instanceof EntityPlayer) {
85 86 + this.world.getServer().getLogger().warning(this.getName() + " was caught trying to crash the server with an invalid pitch");
86 87 + ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Nope");
87 88 + }
88 89 + f1 = 0;
89 90 + }
90 91 + // CraftBukkit end
91 92 +
92 93 this.yaw = f % 360.0F;
93 94 this.pitch = f1 % 360.0F;
94 95 }
95 -@@ -240,7 +309,7 @@
96 +@@ -240,7 +310,7 @@
96 97 if (this.al) {
97 98 MinecraftServer minecraftserver = this.world.getMinecraftServer();
98 99
99 100 - if (minecraftserver.getAllowNether()) {
100 101 + if (true || minecraftserver.getAllowNether()) { // CraftBukkit
101 102 if (!this.isPassenger()) {
102 103 int i = this.V();
103 104
104 -@@ -325,6 +394,27 @@
105 +@@ -325,6 +395,27 @@
105 106 protected void burnFromLava() {
106 107 if (!this.fireProof) {
107 108 this.damageEntity(DamageSource.LAVA, 4.0F);
108 109 +
109 110 + // CraftBukkit start - Fallen in lava TODO: this event spams!
110 111 + if (this instanceof EntityLiving) {
111 112 + if (fireTicks <= 0) {
112 113 + // not on fire yet
113 114 + // TODO: shouldn't be sending null for the block
114 115 + org.bukkit.block.Block damager = null; // ((WorldServer) this.l).getWorld().getBlockAt(i, j, k);
122 123 + } else {
123 124 + // This will be called every single tick the entity is in lava, so don't throw an event
124 125 + this.setOnFire(15);
125 126 + }
126 127 + return;
127 128 + }
128 129 + // CraftBukkit end - we also don't throw an event unless the object in lava is living, to save on some event calls
129 130 this.setOnFire(15);
130 131 }
131 132 }
132 -@@ -365,6 +455,22 @@
133 +@@ -365,6 +456,22 @@
133 134 this.a(this.getBoundingBox().c(d0, d1, d2));
134 135 this.recalcPosition();
135 136 } else {
136 137 + // CraftBukkit start - Don't do anything if we aren't moving
137 138 + // We need to do this regardless of whether or not we are moving thanks to portals
138 139 + try {
139 140 + this.checkBlockCollisions();
140 141 + } catch (Throwable throwable) {
141 142 + CrashReport crashreport = CrashReport.a(throwable, "Checking entity block collision");
142 143 + CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being checked for collision");
145 146 + throw new ReportedException(crashreport);
146 147 + }
147 148 + // Check if we're moving
148 149 + if (d0 == 0 && d1 == 0 && d2 == 0 && this.isVehicle() && this.isPassenger()) {
149 150 + return;
150 151 + }
151 152 + // CraftBukkit end
152 153 this.world.methodProfiler.a("move");
153 154 double d3 = this.locX;
154 155 double d4 = this.locY;
155 -@@ -587,6 +693,26 @@
156 +@@ -587,6 +694,26 @@
156 157 block1.a(this.world, this);
157 158 }
158 159
159 160 + // CraftBukkit start
160 161 + if (positionChanged && getBukkitEntity() instanceof Vehicle) {
161 162 + Vehicle vehicle = (Vehicle) this.getBukkitEntity();
162 163 + org.bukkit.block.Block bl = this.world.getWorld().getBlockAt(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ));
163 164 +
164 165 + if (d6 > d0) {
165 166 + bl = bl.getRelative(BlockFace.EAST);
172 173 + }
173 174 +
174 175 + VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl);
175 176 + world.getServer().getPluginManager().callEvent(event);
176 177 + }
177 178 + // CraftBukkit end
178 179 +
179 180 if (this.playStepSound() && !flag && !this.isPassenger()) {
180 181 double d21 = this.locX - d3;
181 182 double d22 = this.locY - d4;
182 -@@ -618,6 +744,8 @@
183 +@@ -618,6 +745,8 @@
183 184 }
184 185 }
185 186
186 187 + // CraftBukkit start - Move to the top of the method
187 188 + /*
188 189 try {
189 190 this.checkBlockCollisions();
190 191 } catch (Throwable throwable) {
191 -@@ -627,6 +755,8 @@
192 +@@ -627,6 +756,8 @@
192 193 this.appendEntityCrashDetails(crashreportsystemdetails);
193 194 throw new ReportedException(crashreport);
194 195 }
195 196 + */
196 197 + // CraftBukkit end
197 198
198 199 boolean flag2 = this.ai();
199 200
200 -@@ -634,7 +764,16 @@
201 +@@ -634,7 +765,16 @@
201 202 this.burn(1);
202 203 if (!flag2) {
203 204 ++this.fireTicks;
204 205 - if (this.fireTicks == 0) {
205 206 + // CraftBukkit start - Not on fire yet
206 207 + if (this.fireTicks <= 0) { // Only throw events on the first combust, otherwise it spams
207 208 + EntityCombustEvent event = new org.bukkit.event.entity.EntityCombustByBlockEvent(null, getBukkitEntity(), 8);
208 209 + world.getServer().getPluginManager().callEvent(event);
209 210 +
210 211 + if (!event.isCancelled()) {
211 212 + setOnFire(event.getDuration());
212 213 + }
213 214 + } else {
214 215 + // CraftBukkit end
215 216 this.setOnFire(8);
216 217 }
217 218 }
218 -@@ -756,7 +895,7 @@
219 +@@ -756,7 +896,7 @@
219 220 return null;
220 221 }
221 222
222 223 - protected void burn(int i) {
223 224 + protected void burn(float i) { // CraftBukkit - int -> float
224 225 if (!this.fireProof) {
225 226 this.damageEntity(DamageSource.FIRE, (float) i);
226 227 }
227 -@@ -922,6 +1061,13 @@
228 +@@ -922,6 +1062,13 @@
228 229 }
229 230
230 231 public void spawnIn(World world) {
231 232 + // CraftBukkit start
232 233 + if (world == null) {
233 234 + die();
234 235 + this.world = ((CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle();
235 236 + return;
236 237 + }
237 238 + // CraftBukkit end
238 239 this.world = world;
239 240 }
240 241
241 -@@ -1126,6 +1272,18 @@
242 +@@ -1126,6 +1273,18 @@
242 243 try {
243 244 nbttagcompound.set("Pos", this.a(new double[] { this.locX, this.locY, this.locZ}));
244 245 nbttagcompound.set("Motion", this.a(new double[] { this.motX, this.motY, this.motZ}));
245 246 +
246 247 + // CraftBukkit start - Checking for NaN pitch/yaw and resetting to zero
247 248 + // TODO: make sure this is the best way to address this.
248 249 + if (Float.isNaN(this.yaw)) {
249 250 + this.yaw = 0;
250 251 + }
251 252 +
252 253 + if (Float.isNaN(this.pitch)) {
253 254 + this.pitch = 0;
254 255 + }
255 256 + // CraftBukkit end
256 257 +
257 258 nbttagcompound.set("Rotation", this.a(new float[] { this.yaw, this.pitch}));
258 259 nbttagcompound.setFloat("FallDistance", this.fallDistance);
259 260 nbttagcompound.setShort("Fire", (short) this.fireTicks);
260 -@@ -1135,6 +1293,12 @@
261 +@@ -1135,6 +1294,12 @@
261 262 nbttagcompound.setBoolean("Invulnerable", this.invulnerable);
262 263 nbttagcompound.setInt("PortalCooldown", this.portalCooldown);
263 264 nbttagcompound.a("UUID", this.getUniqueID());
264 265 + // CraftBukkit start
265 266 + // PAIL: Check above UUID reads 1.8 properly, ie: UUIDMost / UUIDLeast
266 267 + nbttagcompound.setLong("WorldUUIDLeast", this.world.getDataManager().getUUID().getLeastSignificantBits());
267 268 + nbttagcompound.setLong("WorldUUIDMost", this.world.getDataManager().getUUID().getMostSignificantBits());
268 269 + nbttagcompound.setInt("Bukkit.updateLevel", CURRENT_LEVEL);
269 270 + // CraftBukkit end
270 271 if (this.getCustomName() != null && !this.getCustomName().isEmpty()) {
271 272 nbttagcompound.setString("CustomName", this.getCustomName());
272 273 }
273 -@@ -1210,6 +1374,8 @@
274 +@@ -1210,6 +1375,8 @@
274 275 this.motX = nbttaglist1.e(0);
275 276 this.motY = nbttaglist1.e(1);
276 277 this.motZ = nbttaglist1.e(2);
277 278 +
278 279 + /* CraftBukkit start - Moved section down
279 280 if (Math.abs(this.motX) > 10.0D) {
280 281 this.motX = 0.0D;
281 282 }
282 -@@ -1221,6 +1387,7 @@
283 +@@ -1221,6 +1388,7 @@
283 284 if (Math.abs(this.motZ) > 10.0D) {
284 285 this.motZ = 0.0D;
285 286 }
286 287 + // CraftBukkit end */
287 288
288 289 this.locX = nbttaglist.e(0);
289 290 this.locY = nbttaglist.e(1);
290 -@@ -1278,6 +1445,58 @@
291 +@@ -1278,6 +1446,58 @@
291 292 this.setPosition(this.locX, this.locY, this.locZ);
292 293 }
293 294
294 295 + // CraftBukkit start
295 296 + if (this instanceof EntityLiving) {
296 297 + EntityLiving entity = (EntityLiving) this;
297 298 +
298 299 + // Reset the persistence for tamed animals
299 300 + if (entity instanceof EntityTameableAnimal && !isLevelAtLeast(nbttagcompound, 2) && !nbttagcompound.getBoolean("PersistenceRequired")) {
300 301 + EntityInsentient entityinsentient = (EntityInsentient) entity;
339 340 + bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(entityPlayer.dimension).getWorld();
340 341 + }
341 342 +
342 343 + spawnIn(bworld == null? null : ((CraftWorld) bworld).getHandle());
343 344 + }
344 345 + // CraftBukkit end
345 346 +
346 347 } catch (Throwable throwable) {
347 348 CrashReport crashreport = CrashReport.a(throwable, "Loading entity NBT");
348 349 CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being loaded");
349 -@@ -1337,6 +1556,12 @@
350 +@@ -1337,6 +1557,12 @@
350 351
351 352 public EntityItem a(ItemStack itemstack, float f) {
352 353 if (itemstack.count != 0 && itemstack.getItem() != null) {
353 354 + // CraftBukkit start - Capture drops for death event
354 355 + if (this instanceof EntityLiving && !((EntityLiving) this).forceDrops) {
355 356 + ((EntityLiving) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack));
356 357 + return null;
357 358 + }
358 359 + // CraftBukkit end
359 360 EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY + (double) f, this.locZ, itemstack);
360 361
361 362 entityitem.q();
362 -@@ -1458,6 +1683,24 @@
363 +@@ -1458,6 +1684,24 @@
363 364 if (entity.bB() != this) {
364 365 throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)");
365 366 } else {
366 367 + // CraftBukkit start
367 368 + com.google.common.base.Preconditions.checkState(!entity.passengers.contains(this), "Circular entity riding! %s %s", this, entity);
368 369 +
369 370 + CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle();
370 371 + Entity orig = craft == null ? null : craft.getHandle();
371 372 + if (getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity && entity.world.isChunkLoaded((int) entity.locX >> 4, (int) entity.locZ >> 4, false)) { // Boolean not used
372 373 + VehicleEnterEvent event = new VehicleEnterEvent(
377 378 + CraftEntity craftn = (CraftEntity) entity.getBukkitEntity().getVehicle();
378 379 + Entity n = craftn == null ? null : craftn.getHandle();
379 380 + if (event.isCancelled() || n != orig) {
380 381 + return;
381 382 + }
382 383 + }
383 384 + // CraftBukkit end
384 385 if (!this.world.isClientSide && entity instanceof EntityHuman && !(this.bw() instanceof EntityHuman)) {
385 386 this.passengers.add(0, entity);
386 387 } else {
387 -@@ -1471,6 +1714,22 @@
388 +@@ -1471,6 +1715,22 @@
388 389 if (entity.bB() == this) {
389 390 throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)");
390 391 } else {
391 392 + // CraftBukkit start
392 393 + CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle();
393 394 + Entity orig = craft == null ? null : craft.getHandle();
394 395 + if (getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity) {
395 396 + VehicleExitEvent event = new VehicleExitEvent(
396 397 + (Vehicle) getBukkitEntity(),
397 398 + (LivingEntity) entity.getBukkitEntity()
400 401 + CraftEntity craftn = (CraftEntity) entity.getBukkitEntity().getVehicle();
401 402 + Entity n = craftn == null ? null : craftn.getHandle();
402 403 + if (event.isCancelled() || n != orig) {
403 404 + return;
404 405 + }
405 406 + }
406 407 + // CraftBukkit end
407 408 this.passengers.remove(entity);
408 409 entity.j = 60;
409 410 }
410 -@@ -1614,10 +1873,38 @@
411 +@@ -1610,14 +1870,48 @@
412 + }
413 +
414 + public void setAirTicks(int i) {
415 +- this.datawatcher.set(Entity.az, Integer.valueOf(i));
416 ++ // CraftBukkit start
417 ++ EntityAirChangeEvent event = new EntityAirChangeEvent(this.getBukkitEntity(), i);
418 ++ if (event.isCancelled()) {
419 ++ return;
420 ++ }
421 ++ this.datawatcher.set(Entity.az, Integer.valueOf(event.getAmount()));
422 ++ // CraftBukkit end
411 423 }
412 424
413 425 public void onLightningStrike(EntityLightning entitylightning) {
414 426 - this.damageEntity(DamageSource.LIGHTNING, 5.0F);
415 427 + // CraftBukkit start
416 428 + final org.bukkit.entity.Entity thisBukkitEntity = this.getBukkitEntity();
417 429 + final org.bukkit.entity.Entity stormBukkitEntity = entitylightning.getBukkitEntity();
418 430 + final PluginManager pluginManager = Bukkit.getPluginManager();
419 431 +
420 432 + if (thisBukkitEntity instanceof Hanging) {
441 453 + // CraftBukkit start - Call a combust event when lightning strikes
442 454 + EntityCombustByEntityEvent entityCombustEvent = new EntityCombustByEntityEvent(stormBukkitEntity, thisBukkitEntity, 8);
443 455 + pluginManager.callEvent(entityCombustEvent);
444 456 + if (!entityCombustEvent.isCancelled()) {
445 457 + this.setOnFire(entityCombustEvent.getDuration());
446 458 + }
447 459 + // CraftBukkit end
448 460 }
449 461
450 462 }
451 -@@ -1752,19 +2039,67 @@
463 +@@ -1752,19 +2046,67 @@
452 464 if (!this.world.isClientSide && !this.dead) {
453 465 this.world.methodProfiler.a("changeDimension");
454 466 MinecraftServer minecraftserver = this.h();
455 467 - int j = this.dimension;
456 468 - WorldServer worldserver = minecraftserver.getWorldServer(j);
457 469 - WorldServer worldserver1 = minecraftserver.getWorldServer(i);
458 470 + // CraftBukkit start - Move logic into new function "teleportTo(Location,boolean)"
459 471 + // int j = this.dimension;
460 472 + // WorldServer worldserver = minecraftserver.getWorldServer(j);
461 473 + // WorldServer worldserver1 = minecraftserver.getWorldServer(i);
512 524 }
513 525 + // CraftBukkit end */
514 526
515 527 this.world.kill(this);
516 528 this.dead = false;
517 529 this.world.methodProfiler.a("reposition");
518 530 + /* CraftBukkit start - Handled in calculateTarget
519 531 BlockPosition blockposition;
520 532
521 533 if (i == 1) {
522 -@@ -1793,12 +2128,18 @@
534 +@@ -1793,12 +2135,18 @@
523 535 blockposition = new BlockPosition(this);
524 536 }
525 537
526 538 - worldserver.entityJoinedWorld(this, false);
527 539 + // CraftBukkit end */
528 540 + // CraftBukkit start - Ensure chunks are loaded in case TravelAgent is not used which would initially cause chunks to load during find/create
529 541 + // minecraftserver.getPlayerList().changeWorld(this, j, worldserver, worldserver1);
530 542 + worldserver1.getMinecraftServer().getPlayerList().repositionEntity(this, exit, portal);
531 543 + // worldserver.entityJoinedWorld(this, false); // Handled in repositionEntity
532 544 + // CraftBukkit end
533 545 this.world.methodProfiler.c("reloading");
534 546 Entity entity = EntityTypes.createEntityByName(EntityTypes.b(this), worldserver1);
535 547
536 548 if (entity != null) {
537 549 entity.a(this);
538 550 + /* CraftBukkit start - We need to do this...
539 551 if (j == 1 && i == 1) {
540 552 BlockPosition blockposition1 = worldserver1.q(worldserver1.getSpawn());
541 553
542 -@@ -1806,6 +2147,7 @@
554 +@@ -1806,6 +2154,7 @@
543 555 } else {
544 556 entity.setPositionRotation(blockposition, entity.yaw, entity.pitch);
545 557 }
546 558 + // CraftBukkit end */
547 559
548 560 boolean flag = entity.attachedToPlayer;
549 561
550 -@@ -1813,6 +2155,14 @@
562 +@@ -1813,6 +2162,14 @@
551 563 worldserver1.addEntity(entity);
552 564 entity.attachedToPlayer = flag;
553 565 worldserver1.entityJoinedWorld(entity, false);
554 566 + // CraftBukkit start - Forward the CraftEntity to the new entity
555 567 + this.getBukkitEntity().setHandle(entity);
556 568 + entity.bukkitEntity = this.getBukkitEntity();
557 569 +
558 570 + if (this instanceof EntityInsentient) {
559 571 + ((EntityInsentient)this).unleash(true, false); // Unleash to prevent duping of leads.
560 572 + }
561 573 + // CraftBukkit end
562 574 }
563 575
564 576 this.dead = true;
565 -@@ -1923,6 +2273,11 @@
577 +@@ -1923,6 +2280,11 @@
566 578 }
567 579
568 580 public void setCustomName(String s) {
569 581 + // CraftBukkit start - Add a sane limit for name length
570 582 + if (s.length() > 256) {
571 583 + s = s.substring(0, 256);
572 584 + }
573 585 + // CraftBukkit end
574 586 this.datawatcher.set(Entity.aA, s);
575 587 }
576 588
577 -@@ -1980,7 +2335,26 @@
589 +@@ -1980,7 +2342,26 @@
578 590 }
579 591
580 592 public void a(AxisAlignedBB axisalignedbb) {
581 593 - this.boundingBox = axisalignedbb;
582 594 + // CraftBukkit start - block invalid bounding boxes
583 595 + double a = axisalignedbb.a,
584 596 + b = axisalignedbb.b,
585 597 + c = axisalignedbb.c,
586 598 + d = axisalignedbb.d,
587 599 + e = axisalignedbb.e,
595 607 + if (len > 64) e = b + 64.0;
596 608 +
597 609 + len = axisalignedbb.f - axisalignedbb.c;
598 610 + if (len < 0) f = c;
599 611 + if (len > 64) f = c + 64.0;
600 612 + this.boundingBox = new AxisAlignedBB(a, b, c, d, e, f);
601 613 + // CraftBukkit end
602 614 }
603 615
604 616 public float getHeadHeight() {
605 -@@ -2154,7 +2528,7 @@
617 +@@ -2154,7 +2535,7 @@
606 618 for (Iterator iterator = this.bx().iterator(); iterator.hasNext(); entity.a(oclass, set)) {
607 619 entity = (Entity) iterator.next();
608 620 if (oclass.isAssignableFrom(entity.getClass())) {
609 621 - set.add(entity);
610 622 + set.add((T) entity); // CraftBukkit - decompile error
611 623 }
612 624 }
613 625

Everything looks good. We'll let you know here if there's anything you should know about.

Add shortcut