Commits
md_5 authored 5e5cf84f2cc
1 1 | --- a/net/minecraft/server/Entity.java |
2 2 | +++ b/net/minecraft/server/Entity.java |
3 - | |
3 + | |
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 - | |
52 + | |
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 - | |
62 + | |
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 - | |
96 + | |
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 - | |
105 + | |
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 - | |
133 + | |
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 - | |
156 + | |
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 - | |
183 + | |
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 - | |
192 + | |
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 - | |
201 + | |
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 - | |
219 + | |
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 - | |
228 + | |
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 - | |
242 + | |
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 - | |
261 + | |
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 - | |
274 + | |
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 - | |
283 + | |
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 - | |
291 + | |
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 - | |
350 + | |
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 - | |
363 + | |
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 - | |
388 + | |
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 - | |
411 + | |
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 - | |
463 + | |
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 - | |
534 + | |
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 - | |
554 + | |
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 - | |
562 + | |
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 - | |
577 + | |
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 - | |
589 + | |
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 - | |
617 + | |
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 |